1 条题解

  • 0
    @ 2026-6-30 10:36:22

    网上看到有些题解做法可以被卡掉,所以来发个应该是正解的做法。
    位运算多半要将数据转化为二进制,然后可以独立考虑每一位的贡献。于是将题目从计算每个数在所有二进制位上的贡献转化为计算每个二进制位上所有数字的贡献。
    从高到低分别考虑每个二进制位的贡献,容易贪心地想到若该二进制位上为 00 的数比为 11 的数多,那么 xx 该位取 11 ,反之取 00。但同时还要考虑 xkx\leq k 的限制(即可能第 ii 位选 11 比选 00 优,但第 ii 位选了 11,第 i1i-1 位为了保证 xkx\leq k 就只能选 00,而第 ii 位选 00,第 i1i-1 位选 11 更优),所以不能直接贪心,考虑 dp。
    运用类似数位 dp 的思想,令 f[i][0]f[i][0] 为考虑到二进制第 ii 位,目前为止 xx 仍顶着 kk 的上限时的最大值;f[i][1]f[i][1] 为考虑到二进制第 ii 位,xx 已经小于 kk(即后面的二进制位可以不用考虑 kk 的限制)时的最大值。具体 dp 转移见代码。

    #include<bits/stdc++.h>
    #define ll long long
    #define rg register int
    using namespace std;
    ll read(){
    	char ch=getchar();
    	ll res=0,f=1;
    	while(ch<'0'||ch>'9'){
    		if(ch=='-') f=-1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9'){
    		res=(res<<1)+(res<<3)+ch-'0';
    		ch=getchar();
    	}
    	return res*f;
    }
    void write(ll x){
    	if(x>9) write(x/10);
    	putchar((x%10)^48);
    }
    const int N=1e5+5;
    ll k,l,ans,a[N],f[60][2];
    int main(){
    	int i,j,l,n,m,num1,num2;
    	n=read();k=read();
    	for(i=1;i<=n;i++) a[i]=read();
    	for(i=0;i<=55;i++) f[i][0]=f[i][1]=-1;
    	f[51][0]=0;
    	for(i=50;i>=0;i--){
    		num1=num2=0;
    		for(j=1;j<=n;j++){
    			if((1ll<<i)&a[j]) num1++;
    			else num2++;
    		}
    		if((1ll<<i)&k){
    			if(f[i+1][0]!=-1)
    			f[i][0]=f[i+1][0]+1ll*(1ll<<i)*num2;
    			if(f[i+1][1]!=-1)
    			f[i][1]=f[i+1][1]+1ll*(1ll<<i)*max(num1,num2);
    			if(f[i+1][0]!=-1)
    			f[i][1]=max(f[i][1],f[i+1][0]+1ll*(1ll<<i)*num1);
    		}
    		else{
    			if(f[i+1][0]!=-1)
    			f[i][0]=f[i+1][0]+1ll*(1ll<<i)*num1;
    			if(f[i+1][1]!=-1)
    			f[i][1]=f[i+1][1]+1ll*(1ll<<i)*max(num1,num2);
    		}
    	}
    	write(max(f[0][0],f[0][1]));
    	return 0;
    }
    
    • 1

    信息

    ID
    11619
    时间
    2000ms
    内存
    1024MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者