很好的構造題。
題意
請構造一個長度為 $2^{m+1}$ 的序列 $a$,該序列滿足:
- $\forall i \in[1, 2^{m+1}], a_i \in [0, 2^m-1]$ 且每個數都恰好出現兩次。
- 對於任意一對 $(i, j)$ 滿足 $a_i = a_j$,$a_i\oplus a_{i+1} \oplus \cdots \oplus a_{j-1} \oplus a_j = k$。
$\oplus$ 表示按位異或。
思路
很顯然,當 $k>2^m-1$ 時無解。
再考慮平凡的的情況:
- 當 $m$ 為 $0$,$k$ 為 $0$ 時,只有
0 0
一組解。 - 當 $m$ 為 $1$,$k$ 為 $0$ 時,樣例告訴我們只有
0 0 1 1
一組解。 - 當 $m$ 為 $1$,$k$ 為 $1$ 時,樣例告訴我們無解。
接下來考慮一般情況:
我們知道,$a \oplus a$ 為零,所以只需構造一個序列形如:
$$ 0,1 \dots 2m-1,k,2m-1 \dots 1,0,k $$
該式滿足:對於任意一對 $(i, j)$,$a_i = a_j$,$a_i\oplus a_{i+1} \oplus \cdots \oplus a_{j-1} \oplus a_j = k$。
顯然,這個序列除最後一個元素外是迴文的,並且所有數字都出現了 $2$ 次,正好可以相互抵消。
對於 $k$ 形成的子序列,有一個公式:$0\oplus 1 \oplus 2 \oplus \dots \oplus k=0$,因為在 $0$ 至 $k$ 的序列中,每一位上都出現了偶數個 $1$,全部抵消後便為 $k \oplus 0=k$。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll a,s,d[100005],f;
ll ans;
int main(){
scanf("%lld%lld",&a,&s);
if(a==1&&s==0){
printf("0 0 1 1");
return 0;
}
if(s>=pow(2,a)){
printf("-1");
return 0;
}
for(int i=0;i<pow(2,a);i++){
if(i==s) continue;
printf("%lld ",i);
}
printf("%lld ",s);
for(int i=pow(2,a)-1;i>=0;i--){
if(i==s) continue;
printf("%lld ",i);
}
printf("%lld",s);
return 0;
}