[cf1168E]Xor Permutations

(与题目中下标不同,这里令下标为$[0,2^{k})$来方便运算)

根据异或的性质,显然有解的必要条件是$\bigoplus_{i=0}^{2^{k}-1}a_{i}=0$

在此基础上,我们考虑构造——

定义$solve(i,j,x)$表示在当前$p_{i}$和$q_{i}$的基础上,构造$p'_{i}$与$q'_{i}$,使得:

1.$\forall 0\le t<2^{k}且t\ne i且t\ne j,p_{t}\oplus q_{t}=p'_{t}\oplus q'_{t}$

2.$p_{i}\oplus q_{i}=p'_{i}\oplus q'_{i}\oplus x$,$p_{j}\oplus q_{j}=p'_{j}\oplus q'_{j}\oplus x$

初始令$\forall 0\le i<2^{k},p_{i}=q_{i}=i$,接下来只需要不断执行$solve(i,i+1,\bigoplus_{j=0}^{i}a_{j})$即可

考虑如何执行$solve(i,j,x)$这个操作,首先若$x=0$直接退出,否则继续分析:

由于都是排列,构造可以通过交换来实现,更具体的来说,我们希望找到$t$,使得$p_{i}$与$p_{t}$交换、$q_{j}$与$q_{t}$交换,使得满足$p_{i}\oplus q_{i}=p'_{i}\oplus q'_{i}\oplus x$(不关心$j$以及其他位置)

上述要求即$p_{t}=p_{i}\oplus x$,根据排列总是存在,然后执行这些交换,对之后的情况分类讨论:

1.$t=j$,那么即已经合法(根据$x\ne 0$,必然有$t\ne i$)

2.$t\ne j$,不难发现交换后不合法的位置仅有$t$和$j$,且我们希望将其异或值异或上$q_{t}\oplus q_{j}\oplus x$,不难发现这就是要求执行$solve(t,j,q_{t}\oplus q_{j}\oplus x)$

重复执行上述递归过程,注意到$j$是不变的,只需要证明$i$不会重复经过一个位置,那么递归次数就是$o(2^{k})$(找到$p_{t}$可以预处理做到$o(1)$),总复杂度即$o(2^{2k})$

下面,我们就要来证明$i$不能重复:

反证法,即假设存在重复,不妨假设是与第一次操作相同(可以将之前与其相同的操作看作第一次),即假设这些递归的$i$依次为$I_{1},I_{2},...,I_{m+1}$,其中$\forall 1\le i<j\le m,I_{i}\ne I_{j}$且$I_{m+1}=I_{1}$

假设递归$I_{1}$时是$solve(I_{1},j,x)$,归纳可得递归$I_{i}$时是$solve(I_{i},j,x\oplus q_{j}\oplus q_{I_{i}})$,接下来考虑递归$I_{m}$时整个序列在递归$I_{1}$前的变化——
$$
\begin{pmatrix}I_{1}&I_{2}&I_{3}&...&I_{m-1}&I_{m}&j\\p_{I_{2}}&p_{I_{3}}&p_{I_{4}}&...&p_{I_{m}}&p_{I_{1}}&p_{j}\\q_{I_{1}}&q_{j}&q_{I_{2}}&...&q_{I_{m-2}}&q_{I_{m-1}}&q_{I_{m}}\end{pmatrix}
$$
(其中第一行为下标,第2行和第3行描述当前的$p$和$q$,这里的$p_{i}$和$q_{i}$都是$I_{1}$操作之前$i$位置的值)

由于是$solve(I_{m},j,x\oplus q_{j}\oplus q_{I_{m}})$,同时由于$I_{m+1}=I_{1}$,即$p_{I_{2}}=p_{I_{1}}\oplus x\oplus q_{j}\oplus q_{I_{m}}$

同时,根据$I_{1}$第1次找到$I_{2}$,有$p_{I_{2}}=p_{I_{1}}\oplus x$,代入后不难得到$q_{j}=q_{I_{m}}$,由于是排列,即$I_{m}=j$,即矛盾

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 5005
 4 int n,k,a[N],p[N],q[N],pos[N];
 5 void solve(int i,int j,int x){
 6     if (!x)return;
 7     int t=pos[(p[i]^x)];
 8     swap(p[i],p[t]);
 9     swap(pos[p[i]],pos[p[t]]);
10     swap(q[j],q[t]);
11     if (t!=j)solve(t,j,(q[t]^q[j]^x));
12 }
13 int main(){
14     scanf("%d",&k);
15     n=(1<<k);
16     for(int i=0;i<n;i++){
17         scanf("%d",&a[i]);
18         if (i)a[i]^=a[i-1];
19         p[i]=q[i]=pos[i]=i;
20     }
21     if (a[n-1]){
22         printf("Fou");
23         return 0;
24     }
25     for(int i=0;i<n;i++)solve(i,i+1,a[i]);
26     printf("Shi\n");
27     for(int i=0;i<n;i++)printf("%d ",p[i]);
28     printf("\n");
29     for(int i=0;i<n;i++)printf("%d ",q[i]);
30 }
View Code

 

posted @ 2021-03-26 09:52  PYWBKTDA  阅读(135)  评论(0编辑  收藏  举报