题目大意:
有0~2^M - 1个连续数,规定每个连续数重复一次的情况下,生成一个数列,任意两个相同的数的区间的所有数作异或,并且结果为K,给出K,M,问是否存在这样的数列。
思路:
这道题要尝试找找规律,动动手,比如K = 3 M = 2;可以有 0 3 0 1 2 3 2 1 ,然后我们发现在M > 2,K!= 0 的情况下,数列是: 0 K 0 1......2^(M) - 2,2^(M) - 1,K ,2^(M) - 1,2^(M) - 2,......
这个数列最难解释的是为什么K 到 K,之间满足条件。
这用到了:
其中f(0,n)表示连续n个数异或,在这里f(0, 2^M - 1) = 0 所以除了K 以外的所有数异或都为K。
还有点麻烦是要证明( 2^M - 1)%4 == 3
在这里用到公式:(a+b)%c == (a%c + b%c)%c.
当a%c + b%c为负数,我们要c + a%c + b%c,然后公式变为(c + a%c + b%c)%c
AC代码:
#include <bits/stdc++.h>
using namespace std;
int main(){
int M,K;
cin>>M>>K;
if(K>(pow(2,M)-1) ){printf("-1\n");return 0;}
if(M == 0){
if(K == 0)printf("0 0\n");
}else if(M == 1){
if(K == 1){
printf("-1\n");
}else printf("0 0 1 1\n");
}else{
if(K == 0){
int i ;
for(i =0;i<= (pow(2,M)-1)-1;i++){
printf("%d %d ",i,i);
}
printf("%d %d",i,i);
return 0;
}
printf("0 %d 0 ",K);
// vector<int> pa;
queue<int> fq,seq;
stack<int> sta;
for(int i = 1;i<= (pow(2,M)-1);i++){
if(i == K)continue;
sta.push(i);
fq.push(i);
}
int sz = sta.size();
fq.push(K);
for(int i =0;i<sz;i++){
int no = sta.top();sta.pop();
//cerr<<no<<endl;
seq.push(no);
}
while(!fq.empty()){
printf("%d ",fq.front()); fq.pop();
}
while(! seq.empty()){
if(seq.size() == 1){ printf("%d",seq.front());seq.pop();}
else {
printf("%d ",seq.front());seq.pop();
}
}
}
return 0;
}