题解: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;
} 
posted @ 2025-12-08 12:43  zhangruixiang  阅读(7)  评论(0)    收藏  举报