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

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     else
55     {
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

 

posted @ 2015-09-25 18:00  puck_just_me  阅读(146)  评论(0编辑  收藏  举报