小苯的数组构造

题目链接:https://ac.nowcoder.com/acm/contest/105623/E

题意:

构造一个长度为n的数组满足条件:1.元素都是正数
2.数组元素 按位或和 为x
3.数组元素 按位异或和 为y

思路:

并非猜猜题,考虑拆位贪心
即考虑数组元素(化为二进制)每一位上如何去选择0或者1,使得最后满足条件

发现由于按位或为不进位加法,(因而每个数组元素都小于x),进而得到每个元素的二进制数都为 x二进制数的 子集(x二进制数为0的位都必须为0,为1的位至少有一个元素该位为1)

现在考虑xor,易知x为0的位,对应y的位也一定为0。x为1的位:如果y对应的位为1,说明有奇数个元素该位为1。反之,则说明有偶数个元素该位为1.

对于n的奇偶性分别讨论一下

贪心:为了尽量不出现有一个数组元素为0的情况,所以给每个元素位赋值1的时候漏掉不能总是同一个元素,而是均摊到每个元素的头上

最后要保证构造的数组元素大于0,且xor和按位或的结果满足条件,如果构造不出来,就输出no返回

可以用bitset来表示每个数的二进制+输出答案

bitset

大概是一个强大的位运算工具
下标从0开始,0->31 分别从低位到高位代表一个数的二进制数

//初始化长度为32
biteset<32>bs;
//赋值某个数的二进制位
bitset<32>bs(x);
//用[]访问索引(同数组)  
//用count方法算出其中有多少个1
bs.count();
//用to_ulong()方法转化为整数
int value=bs.to_ulong();
void solve(){
	int n,x,y;cin>>n>>x>>y;
	bitset<32>a(x);
	bitset<32>b(y);
	vector<int>k(32);
	for(int i=0;i<32;i++){
		if(a[i]==0&&b[i]!=0){
			cout<<"NO"<<endl;return;
		}
		if(a[i]==0)k[i]=-1;
		if(a[i]==1){
			if(b[i]==0){
				k[i]=0;//偶数个一 
			}else{
				k[i]=1;//奇数个一 
			}
		}
	}
	int ok= (n&1);
	int skip=1;
	vector<bitset<32>>c(n+1);
	for(int j=0;j<32;j++){
		for(int i=1;i<=n;i++){	
			if(k[j]==-1)c[i][j]=0;
			else if(k[j]==0){
				
				if(ok){
					if(i==skip)continue;
					c[i][j]=1;
				}else{
					c[i][j]=1;
				}
			}
			else if(k[j]==1){
				if(ok){
					c[i][j]=1;
				}else{
					if(i==skip)continue;
					c[i][j]=1;
				}	
			}
		}
		skip=min(skip+1,n);
	}
	int u=0,v=0;
	for(int i=1;i<=n;i++)
	{
	if(c[i].to_ulong()<=0){
		cout<<"NO"<<endl;return;
	}
	u|=c[i].to_ulong();
	v^=c[i].to_ulong();
	}
	if(u!=x||v!=y){
		cout<<"NO"<<endl;return;
	}
	
	cout<<"YES"<<endl;
	for(int i=1;i<=n;i++){
		int v=c[i].to_ulong();
		cout<<v<<' ';
	}
	cout<<endl;
}
posted @ 2025-03-31 16:14  Marinaco  阅读(31)  评论(0)    收藏  举报
//雪花飘落效果