小苯的数组构造
题目链接: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;
}

浙公网安备 33010602011771号