位运算精选
位运算精选
幽幽子的魔法宴会
rating:2000
评述
枚举,贪心。难题,难就难在让你拿到它时无从下手。横亘在本题面前的两个难关,1是选择哪些数,2是如何计算x。想到了要枚举x,但是确实没想到要枚举x的最高位,然后贪心选择数,这样两个难关都迎刃而解了。还需要继续努力。
代码
#include <bits/stdc++.h>
typedef long long ll;
int n,m,k;
ll y;
int a[200005];
const ll inf=4e18;
void solve(){
std::cin>>n>>y;
ll all=0;
for(int i=1;i<=n;i++){
std::cin>>a[i];
all+=a[i];
}
ll ans=8e18;
for(int i=60;i>=0;i--){
ll ad[61]={0};
//当x的最高位在第i位时,所有数在第k位为1时的贡献为ad[k]
for(int j=1;j<=n;j++){
if(!((a[j]>>i)&1)){
for(int k=0;k<=i;k++){
if((a[j]>>k)&1)ad[k]--;
else ad[k]++;
}
}
}
ll sum[61]={0};
for(int j=0;j<=i;j++){
if(ad[j]<0)ad[j]=0;
else if(inf/(1LL<<j)>ad[j]){
ad[j]=(1LL<<j)*ad[j];
}else ad[j]=inf;
}
for(int j=0;j<=i;j++){
sum[j]=ad[j];
if(j)sum[j]+=sum[j-1];
sum[j]=std::min(sum[j],inf);
}
ll x=0;
ll cur=all;
for(int j=i;j>=0;j--){
ll pre;
if(j)pre=sum[j-1];
else pre=0;
//前面的位全取1都无法>y时,不如就j位取1得了。
if(cur+pre<y){
cur+=ad[j];
x+=(1LL<<j);
}
}
if(cur<y)continue;
ans=std::min(ans,x);
}
std::cout<<ans<<'\n';
return;
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
int t = 1, i;
std::cin >> t;
for (i = 0; i < t; i++){
solve();
}
return 0;
}