【搜索】BZOJ 3990: 【Sdoi 2015】排序

来源:互联网 发布:北部战区山东知乎 编辑:程序博客网 时间:2024/05/17 07:03

3990: [SDOI2015]排序

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 336  Solved: 164
[Submit][Status][Discuss]

Description

 小A有一个1-2^N的排列A[1..2^N],他希望将A数组从小到大排序,小A可以执行的操作有N种,每种操作最多可以执行一次,对于所有的i(1<=i<=N),第i中操作为将序列从左到右划分为2^{N-i+1}段,每段恰好包括2^{i-1}个数,然后整体交换其中两段.小A想知道可以将数组A从小到大排序的不同的操作序列有多少个,小A认为两个操作序列不同,当且仅当操作个数不同,或者至少一个操作不同(种类不同或者操作位置不同).

  下面是一个操作事例:
  N=3,A[1..8]=[3,6,1,2,7,8,5,4].
  第一次操作,执行第3种操作,交换A[1..4]和A[5..8],交换后的A[1..8]为[7,8,5,4,3,6,1,2].
  第二次操作,执行第1种操作,交换A[3]和A[5],交换后的A[1..8]为[7,8,3,4,5,6,1,2].
  第三次操作,执行第2中操作,交换A[1..2]和A[7..8],交换后的A[1..8]为[1,2,3,4,5,6,7,8].
 

Input

第一行,一个整数N

第二行,2^N个整数,A[1..2^N]
 

Output

一个整数表示答案

 

Sample Input

3
7 8 5 6 1 2 4 3

Sample Output

6

  网上题解都看不懂。。
  只能%hzwer代码。
  
  黄学长:
  每种交换只能用一次。
  我们从小到大DFS,对于第i次操作我们将序列分成2^(n-i)段,每段长度2^i
  我们找到序列中不是连续递增的段,如果这样的段超过2个,显然就废了

  如果没有这样的段,就不需要执行这个操作

  如果有一个这样的段,判断将这个段的前半部分和后半部分交换后是否连续递增,如果是就交换然后继续DFS

  如果有两个这样的段,判断四种交换情况然后DFS

  

 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cmath> 5   6 using namespace std; 7   8 int a[4098],n; 9  10 long long fac[14],ans=0;11  12 void init(){fac[1]=1;for(int i=2;i<=n;i++)fac[i]=fac[i-1]*i;}13  14 int read()15 {16     int x=0;char ch=getchar();17     while(ch<'0'||ch>'9')ch=getchar();18     while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();19     return x;20 }21  22 void swap(int x,int y,int nu)23 {24     for(int i=x,j=y,nn=0;nn<nu;nn++)25         swap(a[i+nn],a[j+nn]);26 }27  28 void DFS(int dep,int sco)29 {30     if(dep==n)31     {32         ans+=fac[sco];33         return;34     }35     int temp=1<<(dep+1),stack[4]={0,0,0,0},top=0;36     for(int i=1;i<(1<<n);i+=temp)37     {38         if(a[i+(temp>>1)-1]+1!=a[i+(temp>>1)])stack[++top]=i+(temp>>1)-1;39         if(top>2)return;40     }41     if(top==0)42     {43         DFS(dep+1,sco);44         return;45     }46     else if(top==1)47     {48         if(a[stack[1]-(temp>>1)+1]!=a[stack[1]+(temp>>1)]+1)return;49         swap(stack[top]-(temp>>1)+1,stack[top]+1,temp>>1);50         DFS(dep+1,sco+1);51         swap(stack[top]-(temp>>1)+1,stack[top]+1,temp>>1);52         return;53     }54     else55     {56         if(a[stack[1]]+1==a[stack[2]+1]&&a[stack[2]]+1==a[stack[1]+1])57         {58             swap(stack[1]-(temp>>1)+1,stack[2]-(temp>>1)+1,temp>>1);59             DFS(dep+1,sco+1);60             swap(stack[1]-(temp>>1)+1,stack[2]-(temp>>1)+1,temp>>1);61             swap(stack[1]+1,stack[2]+1,temp>>1);62             DFS(dep+1,sco+1);63             swap(stack[1]+1,stack[2]+1,temp>>1);64         }65         else if(a[stack[1]]+1==a[stack[2]-(temp>>1)+1]&&a[stack[1]+(temp>>1)]+1==a[stack[2]+1])66         {67             swap(stack[1]+1,stack[2]-(temp>>1)+1,temp>>1);68             DFS(dep+1,sco+1);69             swap(stack[1]+1,stack[2]-(temp>>1)+1,temp>>1);70         }71         else if(a[stack[2]]+1==a[stack[1]-(temp>>1)+1]&&a[stack[2]+(temp>>1)]+1==a[stack[1]+1])72         {73             swap(stack[2]+1,stack[1]-(temp>>1)+1,temp>>1);74             DFS(dep+1,sco+1);75             swap(stack[2]+1,stack[1]-(temp>>1)+1,temp>>1);76         }77         return;78     }79 }80  81 int main()82 {83     n=read();84     init();85     for(int i=1;i<=(1<<n);i++)86         a[i]=read();87     DFS(0,0);88     printf("%lld",ans);89     return 0;90 }
View Code

 

0 0
原创粉丝点击