题目链接
题目思路
这个题目感觉比较有意思
就是分为三段,让前面两段的数量尽可能接近\(2^i,2^j\)
这样的正确性感觉也不太会证明,不过看起来挺真的...
代码
#include<bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define debug cout<<"I AM HERE"<<endl;
using namespace std;
typedef long long ll;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=2e5+5,inf=0x3f3f3f3f,mod=1e9+7;
const double eps=1e-6;
int n;
int a[maxn];
int cnt[maxn];
int cal(int x,int y){
int sum1=0,sum2=0,sum3=0;
int i;
for(i=1;i<=n;i++){
if(sum1+cnt[i]>x){
break;
}
sum1+=cnt[i];
}
for(;i<=n;i++){
if(sum2+cnt[i]>y){
break;
}
sum2+=cnt[i];
}
sum3=n-sum1-sum2;
int z=1;
while(z<sum3){
z*=2;
}
return x-sum1+y-sum2+z-sum3;
}
signed main(){
int _;scanf("%d",&_);
while(_--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
cnt[a[i]]++;
}
int ans=inf;
for(int i=0;i<=20;i++){
for(int j=0;j<=20;j++){
ans=min(ans,cal(1<<i,1<<j));
}
}
for(int i=1;i<=n;i++){
cnt[i]=0;
}
printf("%d\n",ans);
}
return 0;
}