题意
有一个长度为nnn的数组aaa,每次操作可以给一个数加上2k2^k2k,其中kkk可以是任意非负整数。问最少需要多少次操作来使得该数组的每个元素都相等。
n≤105,ai≤1017n\le10^5,a_i\le10^{17}n≤105,ai≤1017
分析
假设最终每个数都会变为xxx,显然x≥max(ai)x\ge max(a_i)x≥max(ai)那么需要的操作次数就是∑i=1nbitcount(x−ai)\sum_{i=1}^nbitcount(x-a_i)i=1∑nbitcount(x−ai)
设bi=an−ai,t=x−anb_i=a_n-a_i,t=x-a_nbi=an−ai,t=x−an,现在要最小化∑i=1nbitcount(t+bi)\sum_{i=1}^nbitcount(t+b_i)i=1∑nbitcount(t+bi)
考虑dp,当计算到某一位时,如果要计算答案对于每一个iii我们需要知道t+bit+b_it+bi的前一位是否有进位,bib_ibi的这一位和ttt的这一位。其中bib_ibi的这一位已经知道,ttt的这一位可以在dp时枚举,如果我们暴力记录前一位是否进位,状态数为O(2n)O(2^n)O(2n),显然无法接受。
但可以发现t+bit+b_it+bi的前k−1k-1k−1位发生了进位当且仅当t mod 2k+bi mod 2k≥2kt\bmod 2^k+b_i\bmod 2^k\ge2^ktmod2k+bimod2k≥2k
也就是说如果我们把bi mod 2kb_i\bmod 2^kbimod2k按照从小到大排序,那么会发生进位的就是一个后缀,这样状态数就可以做到O(n)O(n)O(n)了。
还有一个结论就是答案不会超过max(bi)max(b_i)max(bi),具体证明可以看官方题解。
对每一位转移时的排序可以做到O(n)O(n)O(n)。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
typedef long long LL;
const int N=100005;
const LL inf=(LL)2e18;
int n,now,s[N];
LL a[N],f[65][N],bin[65],b[N];
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
std::sort(a+1,a+n+1);
for (int i=1;i<=n;i++) a[i]=a[n]-a[i];
for (int i=0;i<=60;i++)
for (int j=0;j<=n;j++)
f[i][j]=inf;
f[0][0]=0;
bin[0]=1;
for (int i=1;i<=60;i++) bin[i]=bin[i-1]*2;
for (int i=1;i<=60;i++)
{
for (int j=1;j<=n;j++) s[j]=s[j-1]+((a[j]&bin[i-1])?1:0);
for (int j=0;j<=n;j++)
{
if (f[i-1][j]==inf) continue;
int was=j-s[j]+s[n]-s[j],cnt=s[j];
f[i][cnt]=std::min(f[i][cnt],f[i-1][j]+was);
was=s[j]+(n-j)-(s[n]-s[j]);cnt=j+s[n]-s[j];
f[i][cnt]=std::min(f[i][cnt],f[i-1][j]+was);
}
int k=0;
for (int j=1;j<=n;j++) if (a[j]&bin[i-1]) b[++k]=a[j];
for (int j=1;j<=n;j++) if (!(a[j]&bin[i-1])) b[++k]=a[j];
for (int j=1;j<=n;j++) a[j]=b[j];
}
printf("%lld\n",f[60][0]);
return 0;
}