【SDOI2015】bzoj3990 排序
2017-01-07 20:52
337 查看
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
一个整数表示答案
按区间大小从小往大考虑,交换了长度为2i的区间以后,再也没法改变每一块长度为2i+1区间内部,所以每一块这样的区间必须已经有序。如果没有无序的可以直接进入下一层,如果有一个无序尝试自身交换,有两个尝试相互交换,否则无解。
因为操作顺序是没有关系的,所以得出一个包含x次操作的方案,实际得到答案数为x!。
每一层最多分四个叉,复杂度O(4n)。
小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
一个整数表示答案
按区间大小从小往大考虑,交换了长度为2i的区间以后,再也没法改变每一块长度为2i+1区间内部,所以每一块这样的区间必须已经有序。如果没有无序的可以直接进入下一层,如果有一个无序尝试自身交换,有两个尝试相互交换,否则无解。
因为操作顺序是没有关系的,所以得出一个包含x次操作的方案,实际得到答案数为x!。
每一层最多分四个叉,复杂度O(4n)。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define LL long long LL fac[20],ans; int a[300010],n; bool inc(int p,int l) { int i; for (i=1;i<(1<<l);i++) if (a[p+i]!=a[p+i-1]+1) return 0; return 1; } void swap(int p1,int p2,int l) { int i; for (i=0;i<(1<<l);i++) swap(a[p1+i],a[p2+i]); } void dfs(int s,int num) { int u1=0,u2=0,v1=0,v2=0,i; if (s==n) { ans+=fac[num]; return; } for (i=1;i<=(1<<n-s-1);i++) if (!inc((1<<s+1)*(i-1)+1,s+1)) { if (!u1) { u1=(1<<s+1)*(i-1)+1; u2=(1<<s+1)*(i-1)+1+(1<<s); } else { if (!v1) { v1=(1<<s+1)*(i-1)+1; v2=(1<<s+1)*(i-1)+1+(1<<s); } else return; } } if (!u1) dfs(s+1,num); else { if (!v1) { swap(u1,u2,s); if (inc(u1,s+1)) dfs(s+1,num+1); swap(u1,u2,s); } else { swap(u1,v1,s); if (inc(u1,s+1)&&inc(v1,s+1)) dfs(s+1,num+1); swap(u1,v1,s); swap(u1,v2,s); if (inc(u1,s+1)&&inc(v1,s+1)) dfs(s+1,num+1); swap(u1,v2,s); swap(u2,v1,s); if (inc(u1,s+1)&&inc(v1,s+1)) dfs(s+1,num+1); swap(u2,v1,s); swap(u2,v2,s); if (inc(u1,s+1)&&inc(v1,s+1)) dfs(s+1,num+1); swap(u2,v2,s); } } } int main() { int i; scanf("%d",&n); for (i=1;i<=(1<<n);i++) scanf("%d",&a[i]); fac[0]=1; for (i=1;i<=n;i++) fac[i]=fac[i-1]*i; dfs(0,0); printf("%lld\n",ans); }
相关文章推荐
- 【BZOJ3990】【SDOI2015】排序
- 【搜索】BZOJ 3990: 【Sdoi 2015】排序
- BZOJ 3990 Sdoi2015 排序 DFS
- bzoj3990 [SDOI2015]排序(搜索)
- BZOJ 3990 [SDOI2015]排序 ——搜索
- 【bzoj3990】[SDOI2015]排序 DFS
- [bzoj3990][SDOI2015]排序-搜索
- [BZOJ3990][SDOI2015]排序(DFS)
- 【搜索】BZOJ 3990: 【Sdoi 2015】排序
- 【BZOJ 3990】 [SDOI2015]排序
- [SDOI2015][BZOJ3990] 排序
- BZOJ 3990: [SDOI2015]排序
- Bzoj3990 [SDOI2015]排序
- 【bzoj3990】【SDOI2015】【排序】【dfs】
- 【BZOJ3990】【SDOI2015】排序
- bzoj3990 [SDOI2015]排序 dfs
- BZOJ 3990 [SDOI2015]排序
- BZOJ.3990.[SDOI2015]排序(DFS)
- BZOJ 3990 [SDOI 2015] 排序 解题报告
- bzoj 3990: [SDOI2015]排序 dfs