【搜索】BZOJ 3990: 【Sdoi 2015】排序
3990: [SDOI2015]排序
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 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
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 }