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);
    }
    
  • 相关阅读:
    LevelDB的源码阅读(四) Compaction操作
    LevelDB的源码阅读(三) Get操作
    LevelDB的源码阅读(三) Put操作
    高级测试/测试开发技能
    IM测试功能点
    深入理解--SSM框架中Dao层,Mapper层,controller层,service层,model层,entity层都有什么作用
    Jmeter非GUI分布式测试
    全套支付宝系统架构(内部架构图)【收藏】
    Jmeter
    报表类相关测试范围总结
  • 原文地址:https://www.cnblogs.com/Y25t/p/15344549.html
Copyright © 2011-2022 走看看