位运算精选

位运算精选

幽幽子的魔法宴会

rating:2000

https://ac.nowcoder.com/acm/contest/106509/D

评述

枚举,贪心。难题,难就难在让你拿到它时无从下手。横亘在本题面前的两个难关,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;
}
posted @ 2025-04-04 14:49  califeee  阅读(5)  评论(0)    收藏  举报