CF1188D Make Equal 题解
询问把一个长为 \(n\) 的数组变成同一个数的最小操作次数,一次操作是给 \(a_i \leftarrow a_i+2^k\)。
先给 \(a\) 排序,则令最终所有数为 \(x+a_n\),我们就要最小化 \(\sum_{i=1}^n \mathrm{popcount}(x+a_n-a_i)\),直接令 \(a_i=a_n-a_i\)。
要最小化 \(\sum \mathrm{popcount}(x+a_i)\),我们就按位从低到高考虑,我们需要知道 \(a_i\) 第 \(j\) 位的值,\(x\) 第 \(j\) 位的值,以及在 \(j-1\) 位进位了几次。其中 \(a_i\) 我们是知道的,\(x\) 是需要我们分两种情况决策的,那关键就在于上一位进位了几次。
做一个巧妙的考量,在第 \(j\) 位进位的次数,肯定是在 \(\bmod 2^j\) 下最大的那几个 \(a_i\) 进位。那我们就每一位都把 \(a\) 按照 \(\bmod 2^j\) 从小到大排序。记 \(sum_{i,0/1}\) 表示排序后的数组这一位上 \(0/1\) 数量的前缀和,\(f_{i,j}\) 表示完成了 \(0~i-1\) 位,第 \(i-1\) 位向第 \(i\) 位进位了 \(j\) 次时最小的 \(\mathrm{popcount}\)。
分两种情况考虑转移:
1.当 \(x\) 这一位为 \(0\) 时,\(x\) 对原数组没有影响,新增的 \(1\) 个数 \(cst\) 为原本不进位的数里 \(1\) 的个数 \(sum_{n-j,1}\),加上原本进位的数里为 \(0\) 的个数 \(sum_{n,0}-sum_{n-j,0}\),因为原本是 \(0\) 进位就变成 \(1\) 了。此时新的进位数 \(cry\) 为原本进位的数里为 \(1\) 的数个数。
2.当 \(x\) 这一位为 \(1\) 时,\(x\) 对这一位的数组都会再加 \(1\)。\(cst\) 等于原本不进位且是 \(0\) 的数个数加上原本进位且是 \(1\) 的数个数,因为 \(1+1+1\) 还是 \(1\)。\(cry\) 等于除了原本是 \(0\) 不进位里的数的所有数。
时间复杂度 \(O(n \log^2 n)\)。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define _int __int128
#define ull unsigned long long
#define pii pair<int,int>
#define fst first
#define scd second
#define pq priority_queue
#define mkp make_pair
#define popcount(x) __builtin_popcount(x)
#define endl '\n'
int n;
const int N = 1e5+10,V=61;
int a[N],id[N],cur;
int f[V+4][N],sum[N][2];
bool cmp(int x,int y){
return (a[x]&((1ll<<cur)-1))<(a[y]&((1ll<<cur)-1));
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
id[i]=i;
}
memset(f,0x3f,sizeof(f));
f[0][0]=0;
sort(a+1,a+1+n);
for(int i=1;i<=n;i++)a[i]=a[n]-a[i];
for(int i=0;i<V;i++){
memset(sum,0,sizeof(sum));
cur=i;
sort(id+1,id+1+n,cmp);
for(int j=1;j<=n;j++){
sum[j][0]=sum[j-1][0];sum[j][1]=sum[j-1][1];
sum[j][(a[id[j]]>>i)&1]++;
}
for(int j=0;j<=n;j++){
int cst=sum[n-j][1]+(sum[n][0]-sum[n-j][0]);
int cry=sum[n][1]-sum[n-j][1];
f[i+1][cry]=min(f[i+1][cry],f[i][j]+cst);
cst=sum[n][1]-sum[n-j][1]+sum[n-j][0];
cry=n-sum[n-j][0];
f[i+1][cry]=min(f[i+1][cry],f[i][j]+cst);
}
}
cout<<f[V][0];
return 0;
}

浙公网安备 33010602011771号