zoukankan      html  css  js  c++  java
  • 《浅谈保序回归问题》学习笔记

    保序回归问题

    偏序关系

    定义二元关系 (preceq) 为集合 (S) 上的偏序关系,满足:

    • 自反性:(forall xin S,xpreceq x)
    • 反对称性:(forall x,yin S,xpreceq yland ypreceq xRightarrow x=y)
    • 传递性:(forall x,y,zin S,xpreceq yland ypreceq zRightarrow xpreceq z)

    (L_p) 问题

    问题: 给定 DAG (G=(V={v_i}_{i=1}^n,E))、代价函数 ({(y_i,w_i)}_{i=1}^n)。定义偏序关系 (v_ipreceq v_j) 当且仅当 (G) 中存在 (v_i)(v_j) 的路径。

    求出

    [min{sum_{i=1}^nw_i|f_i-y_i|^p |forall v_{i}preceq v_j,f_ileq f_j},p<infty\ min{max_{i=1}^nw_i|f_i-y_i| |forall v_{i}preceq v_j,f_ileq f_j},p=infty ]

    序列 (z) 向集合 (S={a,b}) 取整

    ({z_i}_{i=1}^ngets {min{b,max{a,z_i}}}_{i=1}^n)

    点集 (U)(L_p) 均值

    使得 (sum_{v_iin U}w_i|y_i-k|^p(p<infty))(max_{v_iin U}w_i|y_i-k|(p=infty)) 取到最小值的 (k)

    一般问题的解法

    (L_p)(S={a,b}(a<b)) 问题

    (L_p) 问题中增加 (forall 1leq ileq n,aleq f_ileq b) 的限制。

    (L_1) 问题解法

    引理:(forall 1leq ileq n,y_i otin (a,b)) 且存在最优解序列 ({z_i}_{i=1}^n,s.t.forall 1leq ileq n,z_i otin (a,b)),那么对于 (S={a,b}) 问题的最优解 (z^S),都存在一个原问题的最优解 (z),满足 (z)(S) 取整后得到 (z^S)

    对于 (L_1) 问题的最优解 (z)(z) 中的元素一定在 (y) 构成的集合 ({Y_i}_{i=1}^k(forall 1leq i<k,Y_i<Y_{i+1})) 中。于是可以进行整体二分:当二分到 (Y_{[l,r]}) 时,求出 (S={Y_{mid},Y_{mid+1}}) 问题的最优解,然后通过这一组解将此区间内的节点重新划分至 (Y_{[l,mid]})(Y_{[mid+1,r]}) 递归求解。

    (L_p(1<p<infty)) 问题解法

    引理: (forall 1<p<infty,Usubset V)(U)(L_p) 均值是唯一的。

    引理:(forall Usubset V)(U)(L_p) 均值不在 ((a,b)(a<b)) 中且存在最优解 ({z_i}_{i=1}^n,s.t.forall 1leq ileq n,z_i otin (a,b))。那么对于代价函数为 ((y',w'))(L_1) 问题的最优解 ( ilde{z}),存在原问题的最优解 ({z_i}_{i=1}^n,s.t.forall 1leq ileq n,z_ileq aLeftrightarrow ilde{z}_i=0)。其中:

    [(y'_i,w'_i)=left{egin{aligned}(0,w_i[(b-y_i)^p-(a-y_i)^p]),y_ileq a\(1,w_i[(y_i-a)^p-(y_i-b)^p]),y_i>aend{aligned} ight. ]

    类似于 (L_1) 问题,可以进行在实数上的整体二分:当二分到 ([l,r]) 时,选定一个极小的正实数 (epsilon),那么 ((a,b)=(mid,mid+epsilon)) 时满足上述条件,求出 ( ilde{z}),进行递归求解(不影响结果地,可以将 (w') 同时除以 (epsilon),变为原表达式在 (mid) 处的导数)。

    (L_1)(S) 问题解法

    对于一般 DAG,可以抽象为最小权闭合子图问题,用网络流解决。

    对于树/仙人掌/多维偏序,可以根据特殊性质进行 dp 求解。

    (L_infty) 问题的解法与扩展

    二分法

    二分答案+DAG 上 dp。

    问题拓展

    问题: 在满足 (L_infty) 的限制下,对于每个 (1leq kleq n) 求出 (min{max_{i=1}^kw_i|f_i-y_i|})。另外,增加条件 (forall 1leq i<jleq n,v_ipreceq v_j)

    定义 (err(v_i,r)=w_i|r-y_i|)(mean(v_i,v_j)=frac{w_iy_i+w_jy_j}{w_i+w_j})

    (v_ipreceq v_jland y_i>y_j) 时,(mean\_err(v_i,v_j)=max{err(v_i,mean(v_i,v_j)),err(v_j,mean(v_i,v_j))});否则 (mean\_err(v_i,v_j)=0)

    引理: 对于任意 (L_infty) 问题,整张图的答案为 (max{mean\_err(v_i,v_j})

    (pre(v_i)=max{mean\_err(v_j,v_i)|v_jpreceq v_i})

    那么对于任意 DAG 可以 (O(n^2)) 求出 (pre),进而求出答案。对于新增加的条件,可以通过维护凸包以做到 (O(nlog n))

    例题

    [省选联考 2020 A 卷] 魔法商店

    简要题意

    给定一个非负整数集合,每个元素有一个权值,你可以修改每个元素的权值各一次,代价为修改前后权值差的平方。指定该集合的两组不同线性基 (A,B),要求 (A) 为所有线性基中权值和最小的,(B) 为最大的。求出最小代价。

    题解

    要求等价于 (A) 中每个元素的权值都要小于等于能替换该元素的其他元素的权值,(B) 反之。建立出偏序关系然后跑 (L_2) 问题即可。

    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #define inf 0x3f3f3f3f
    #define ull unsigned long long
    #define N 1005
    #define M 70
    
    namespace XB{
    	#define W 64
    	ull d[W];
    	inline void cl(){
    		for(int i=0;i<W;i++)
    			d[i]=0;
    	}
    	inline void ins(ull x){
    		for(int i=W-1;i>=0;i--)
    			if((x>>i)&1){
    				if(!d[i]){
    					d[i]=x;
    					break;
    				}
    				x^=d[i];
    			}
    	}
    	inline bool chk(ull x){
    		for(int i=W-1;i>=0;i--)
    			if((x>>i)&1)
    				x^=d[i];
    		return x>0;
    	}
    }
    
    namespace MF{
    	int n,s,t;
    	
    	int hd[N],_hd;
    	struct edge{
    		int v,f,nxt;
    	}e[N*M<<1];
    	inline void addedge(int u,int v,int f){
    		e[++_hd]=(edge){v,f,hd[u]};
    		hd[u]=_hd;
    		e[++_hd]=(edge){u,0,hd[v]};
    		hd[v]=_hd;
    	}
    	
    	inline void init(int n_,int s_,int t_){
    		for(int i=1;i<=n;i++)
    			hd[i]=0;
    		_hd=1;
    		n=n_,s=s_,t=t_;
    	}
    	
    	std::queue<int> q;
    	int cur[N],dis[N];
    	inline bool bfs(){
    		for(int i=1;i<=n;i++)
    			cur[i]=hd[i];
    		for(int i=1;i<=n;i++)
    			dis[i]=inf;
    		dis[s]=0;
    		q.push(s);
    		while(q.size()){
    			int u=q.front();
    			q.pop();
    			for(int i=hd[u];i;i=e[i].nxt){
    				int v=e[i].v,f=e[i].f;
    				if(f&&dis[v]>dis[u]+1){
    					dis[v]=dis[u]+1;
    					q.push(v);
    				}
    			}
    		}
    		return dis[t]<inf;
    	}
    	inline int dfs(int u,int lmt){
    		if(u==t||!lmt)
    			return lmt;
    		int res=0;
    		for(int i=cur[u];i;i=e[i].nxt){
    			cur[u]=i;
    			int v=e[i].v,f=e[i].f;
    			if(dis[v]!=dis[u]+1)
    				continue;
    			f=dfs(v,std::min(lmt,f));
    			e[i].f-=f,e[i^1].f+=f;
    			lmt-=f,res+=f;
    			if(!lmt)
    				break;
    		}
    		return res;
    	}
    	inline void sol(){
    		while(bfs())
    			dfs(s,inf);
    	}
    }
    
    int n,m,y[N],a[M],b[M];
    ull c[N];
    
    std::vector<int> E[N];
    
    int f[N],p[N],id[N],q[N];
    inline void sol(int L,int R,int l,int r){
    	if(l>r)
    		return;
    	if(L==R){
    		for(int i=l;i<=r;i++)
    			f[p[i]]=L;
    		return;
    	}
    	int mid=(L+R)>>1;
    	MF::init(r-l+3,r-l+2,r-l+3);
    	for(int i=l;i<=r;i++)
    		id[p[i]]=i-l+1;
    	for(int i=l;i<=r;i++){
    		int u=p[i],w=2*(y[u]-mid)-1;
    		if(w>0)
    			MF::addedge(MF::s,id[u],w);
    		else
    			MF::addedge(id[u],MF::t,-w);
    		for(auto v:E[u])
    			if(id[v])
    				MF::addedge(id[u],id[v],inf);
    	}
    	MF::sol();
    	int pm=l-1;
    	for(int i=l;i<=r;i++)
    		if(MF::dis[id[p[i]]]==inf)
    			q[++pm]=p[i];
    	int tmp=pm;
    	for(int i=l;i<=r;i++)
    		if(MF::dis[id[p[i]]]<inf)
    			q[++tmp]=p[i];
    	for(int i=l;i<=r;i++)
    		p[i]=q[i];
    	for(int i=l;i<=r;i++)
    		id[p[i]]=0;
    	sol(L,mid,l,pm);
    	sol(mid+1,R,pm+1,r);
    }
    
    ull ans;
    
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    		scanf("%llu",&c[i]);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&y[i]);
    	for(int i=1;i<=m;i++)
    		scanf("%d",&a[i]);
    	for(int i=1;i<=m;i++)
    		scanf("%d",&b[i]);
    	for(int i=1;i<=m;i++){
    		XB::cl();
    		for(int j=1;j<=m;j++)
    			if(j!=i)
    				XB::ins(c[a[j]]);
    		for(int j=1;j<=n;j++)
    			if(j!=a[i]&&XB::chk(c[j]))
    				E[a[i]].push_back(j);
    	}
    	for(int i=1;i<=m;i++){
    		XB::cl();
    		for(int j=1;j<=m;j++)
    			if(j!=i)
    				XB::ins(c[b[j]]);
    		for(int j=1;j<=n;j++)
    			if(j!=b[i]&&XB::chk(c[j]))
    				E[j].push_back(b[i]);
    	}
    	for(int i=1;i<=n;i++)
    		p[i]=i;
    	sol(0,(int)1e6,1,n);
    	for(int i=1;i<=n;i++)
    		ans+=1ull*(f[i]-y[i])*(f[i]-y[i]);
    	printf("%llu
    ",ans);
    }
    
  • 相关阅读:
    hdu 4710 Balls Rearrangement()
    hdu 4707 Pet(DFS水过)
    hdu 4706 Children's Day(模拟)
    hdu 4712 Hamming Distance(随机函数暴力)
    csu 1305 Substring (后缀数组)
    csu 1306 Manor(优先队列)
    csu 1312 榜单(模拟题)
    csu 1303 Decimal (数论题)
    网络爬虫
    Python处理微信利器——itchat
  • 原文地址:https://www.cnblogs.com/Y25t/p/15344549.html
Copyright © 2011-2022 走看看