最近好像老是跟构造过不去눈_눈
题意:给出n与x,要求先说可不可以给出n个数字使其异或和为x,如果可以,那么输出这n个数字。
思路: 1、首先要知道(x^y^(x+y))=0,手动列一下式子就粗来了눈_눈
2、然后0和k(k为任何数字)异或的结果是k(当年pascal的基础大概是被我吃了)
一开始定义的max1和max2的位数极长,换算成十进制超过六位,为的是防止输出重复;而从1输出到n-3纯粹是凑位数,事实上只要三位就可以了。
当1到n-3的异或和为x时,凑一个零。
当1到n-3的异或和不为x时,想办法把它凑成x,那么这时候就需要活用第二条思路了:0^k=k——->x^(y^z)^y^z=x
注意:max1和max2必须为2的幂次方,因为这样的话在2进制下后面跟着一串的零,使其与比其小的数异或时能保证稳定的增大,避免与1~n-3有重复。
Gloria的补充:
考虑到异或的性质那么肯定要有两个相同的,怎么让我们能让他们不同呢?其实想明白了其实很简单,1e5大约是17为,1e6为20位.
这里我们为了让他们不同构造两个数 (1<<17) 和(1<<18) 这样和他们异或的和一定不同,因为17 18 位都是0
肯定不一样了,剩下的n-2个数,有n-3个我们让他们从1-n-3输出,最后一个数构造为 x
^(1…n-3)^(1<<17)^(1<<18)。这样就很简单的保证了n个数互不相同。
大晚上的,看题解。没看懂最开始为啥要从1输出到n-3,于是乎半夜三点骚扰大狗……我果然还是太菜了QWQ
#include<bits/stdc++.h>
using namespace std;
const int max1=1<<17;
const int max2=1<<18;
int main(){
int n,x,tot=0;
while(~scanf("%d%d",&n,&x)){
if(n==2 && x==0){
printf("NO\n");
break;
}
if(n==1){
printf("YES\n%d\n",x);
break;
}
if(n==2){
printf("YES\n0 %d\n",x);
break;
}
printf("YES\n");
for(int i=1;i<=n-3;i++){
printf("%d ",i);
tot^=i;
}
if(tot==x){
cout<<max1+max2<<" "<<max1<<" "<<max2<<endl;
}
else cout<<"0 "<<max1<<" "<<((max1^tot)^x)<<endl;
}
return 0;
}
结论:对异或运算还不够熟悉,题目做得太少……
掌握好基本公式很重要啊