zoukankan      html  css  js  c++  java
  • CF1188D Make Equal

    题解

    (a_1,a_2,dots,a_n) 从小到大排序,若 (a_n) 加上了 (x),显然让所有数最终都等于 (a_n+x) 是最优的。

    所以就是求 (sum_{i=1}^n operatorname{popcount}(x+a_n-a_i)) 的最小值。

    对于所有 (i),令 (a_igets a_n-a_i)

    我们发现,当一个位 (k),数 (a_i) 满足如下三个条件中的至少两个时,它就会产生进位:

    1. (a_i) 的第 (k) 位为 (1)
    2. (a_i) 的第 (k-1) 位产生了进位;
    3. (x) 的第 (k) 位为 (1)

    对于每个位 (k),按照 (a_imod 2^{k+1}) 从大到小排序,并记该数组为 (b_{k}),那么能产生进位的数是 (b_k) 的一个前缀。

    (f_{i,j}) 为考虑最低的 (i) 位,第 (i) 位有 (j) 个数产生进位的最小答案。

    (cnt_{i,j})(b_i) 的前 (j) 个元素中,有多少个元素的第 (i+1) 位为 (1)(l_i)(sum_{j=1}^n [a_joperatorname{and} 2^i=2^i])。分类讨论 (x) 的第 (i) 位:

    • (x operatorname{and} 2^i=1)

      [f_{i,j}=min_{cnt_{i-1,k}=j}{f_{i-1,k}+k}+l_i-2j\forall 1le ile log V+1,1le jle l_i ]

    • (x operatorname{and} 2^i=0)

      [f_{i,j}=min_{l_i+k-cnt_{i-1,k}=j}{f_{i-1,k}+cnt_{i-1,k}+(n-l_i)-(k-cnt_{i-1,k})}\forall 1le ile log V+1,l_ile jle n ]

    时间复杂度 (mathcal{O}(nlog Vlog n)),若使用基数排序则为 (mathcal{O}(nlog V))

    代码

    #include <cstdio>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    #define For(Ti,Ta,Tb) for(int Ti=(Ta);Ti<=(Tb);++Ti)
    #define Dec(Ti,Ta,Tb) for(int Ti=(Ta);Ti>=(Tb);--Ti)
    template<typename T>
    void Read(T &_x){
    	_x=0;int _f=1;
    	char ch=getchar();
    	while(!isdigit(ch)) _f=(ch=='-'?-1:_f),ch=getchar();
    	while(isdigit(ch)) _x=_x*10+(ch^48),ch=getchar();
    	_x*=_f;
    }
    template<typename T,typename... Args>
    void Read(T &_x,Args& ...others){
    	Read(_x);Read(others...);
    }
    typedef long long ll;
    const int N=1e5+5,LogV=59;
    int n,id[LogV][N],f[LogV][N],l[LogV],cnt[LogV][N],g1[N],g2[N];
    ll a[N],num[LogV][N];
    void Store(int _i,int _j){
    	g1[cnt[_i][_j]]=min(g1[cnt[_i][_j]],f[_i][_j]+_j);
    	g2[_j-cnt[_i][_j]]=min(g2[_j-cnt[_i][_j]],f[_i][_j]+2*cnt[_i][_j]-_j);
    }
    int main(){
    	Read(n);
    	For(i,1,n) Read(a[i]);
    	sort(a+1,a+n+1);
    	For(i,1,n){
    		a[i]=a[n]-a[i];
    		for(ll j=0,cur=a[i]&1;j<LogV;++j,cur=cur|(a[i]&(1LL<<j))){
    			id[j][i]=i,num[j][i]=cur;
    		}
    	}
    	For(j,0,LogV-1){
    		sort(id[j]+1,id[j]+n+1,[j](int x,int y){return num[j][x]>num[j][y];});
    		For(i,1,n){
    			l[j]+=bool(a[i]&(1LL<<j));
    			cnt[j][i]=cnt[j][i-1]+bool(a[id[j][i]]&(1LL<<(j+1)));
    		}
    	}
    	memset(f,0x3f,sizeof f);
    	memset(g1,0x3f,sizeof g1);
    	memset(g2,0x3f,sizeof g2);
    	f[0][0]=l[0],f[0][l[0]]=min(f[0][l[0]],n-l[0]);
    	Store(0,0),Store(0,l[0]);
    	For(i,1,LogV-1){
    		For(j,0,l[i]){
    			f[i][j]=g1[j]+l[i]-2*j;
    		}
    		For(j,l[i],n){
    			f[i][j]=min(f[i][j],g2[j-l[i]]+n-l[i]);
    		}
    		memset(g1,0x3f,sizeof g1);
    		memset(g2,0x3f,sizeof g2);
    		For(j,0,n){
    			Store(i,j);
    		}
    	}
    	printf("%d
    ",f[LogV-1][0]);
    	return 0;
    }
    
    Written by Alan_Zhao
  • 相关阅读:
    nefu 628 Garden visiting
    codeforces 814 C. An impassioned circulation of affection 【尺取法 or DP】
    bzoj 2111: [ZJOI2010]Perm 排列计数 (dp+卢卡斯定理)
    Codeforces Round #423 (Div. 2)
    hdu 5955 Guessing the Dice Roll 【AC自动机+高斯消元】
    poj1322 Chocolate 【 概率DP 】
    poj 3414 Pots 【BFS+记录路径 】
    hdu5194 DZY Loves Balls 【概率论 or 搜索】
    51nod 1515 明辨是非 [并查集+set]
    hdu 1175 连连看 [DFS]
  • 原文地址:https://www.cnblogs.com/alan-zhao-2007/p/cf1188d-sol.html
Copyright © 2011-2022 走看看