• [cf1168E]Xor Permutations


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

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

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

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

    1.$forall 0le t<2^{k}且t e i且t e 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 0le i<2^{k},p_{i}=q_{i}=i$,接下来只需要不断执行$solve(i,i+1,igoplus_{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 e 0$,必然有$t e i$)

    2.$t e 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 1le i<jle m,I_{i} e I_{j}$且$I_{m+1}=I_{1}$

    假设递归$I_{1}$时是$solve(I_{1},j,x)$,归纳可得递归$I_{i}$时是$solve(I_{i},j,xoplus q_{j}oplus q_{I_{i}})$,接下来考虑递归$I_{m}$时整个序列在递归$I_{1}$前的变化——
    $$
    egin{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,xoplus q_{j}oplus q_{I_{m}})$,同时由于$I_{m+1}=I_{1}$,即$p_{I_{2}}=p_{I_{1}}oplus xoplus 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
    ");
    27     for(int i=0;i<n;i++)printf("%d ",p[i]);
    28     printf("
    ");
    29     for(int i=0;i<n;i++)printf("%d ",q[i]);
    30 }
    View Code
  • 相关阅读:
    SharePoint 2013 工作流之使用Visio设计篇
    SharePoint 2013 工作流之Visual Studio开发示例篇
    Ajax
    jq判断上下滚动
    元素(绝对定位)水平垂直居中
    css3动画:animation
    自定义button上传按钮
    Json
    页面滚动到顶部
    HDU 4358 Boring counting dfs序+莫队算法
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14580614.html
Copyright © 2020-2023  润新知