题解:P14664 [KenOI 2025] 异或题
题目分析
按位贪心。
用 \(n_i\) 表示 \(n\) 的二进制第 \(i\) 位的值。
- 如果 \(n_i=0\),我们肯定选择 \(a_i=b_i=1\),因为 \(1+1>0+0\)。这样 \(a,b\) 都会加上 \(2^{n_i}\)。注意:如果 \(a+2^{n_i}\) 或者 \(b+2^{n_i}>n\) 了,只能选择 \(a,b\) 都不变。
- 如果 \(n_i=1\),选择 \(a,b\) 中较小的那个并加上 \(2^{n_i}\)。这是为了尽可能晚达到 \(a+2^{n_i}\) 或者 \(b+2^{n_i}>n\) 的情况。
注意判断 \(n=0\),不然会死循环超时。
为啥我常数这么大。
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
int n;
cin>>n;
//a^b=n
if(n==0){
cout<<0<<endl;
return ;
}
int k=ceil(log2(n));
int a=0,b=0;
if((1<<(int)log2(n))==n)k++;//上面的k是统计n转为二进制的位数
for(int i=k-1;i>=0;i--){
int w=(n&(1<<i))>>i;
//ai^bi=w
if(w==0){
if(a+(1<<i)>n||b+(1<<i)>n)continue;
else a+=(1<<i),b+=(1<<i);
}
//剩下是w=1的情况(w=0没有贡献)
if(a<=b)a+=(w<<i);
else b+=(w<<i);
}
cout<<a+b<<endl;
}
signed main(){
int T,t;
ios::sync_with_stdio(0);
cin.tie(0);
cin>>T;
t=T;//好像没有意义
while(T--){
solve();
}
return 0;
}

浙公网安备 33010602011771号