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
原文地址:https://www.cnblogs.com/alan-zhao-2007/p/cf1188d-sol.html