BZOJ 3990: [SDOI2015]排序 [搜索]

3990: [SDOI2015]排序

题意:\(2^n\)的一个排列,给你n种操作,第i种把每\(2^{i-1}\)个数看成一段,交换任意两段。问是这个序列有序的操作方案数,两个操作序列不同,当且仅当操作个数不同,或者至少一个操作不同(种类不同或者操作位置不同).


R1D1T1

先玩一下样例

发现操作的顺序其实没有影响

从小到大考虑,设当前处理的有n段,可以分成\(\frac{n}{2}\)个二元组\((a_i, a_{i+1})\),每个都要满足\(a_i +1 = a_{i+1}\),找出有几个不满足,如果\(\le 2\)个那么枚举如何交换然后再处理\(\frac{n}{2}\)段的时候

注意每种成立的交换就要继续搜索...一开始没这么做然后35分...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=(1<<12) + 5, INF=1e9+5;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

int bin, n, t[15][N], fac[N]; ll ans=0;
inline bool check(int *a, int x, int y) {return a[x]+1 == a[x+1] && a[y]+1 == a[y+1];}
inline void ready(int *a, int n) {
	for(int i=1; i<=n; i++) a[i] = a[i*2-1]/2 + 1;
}
void dfs(int d, int n, int now) { //printf("dfs %d %d  %d\n",d,n,now);
	if(d>=bin) {ans += fac[now]; return;}
	int *a = t[d], *b = t[d+1];
	//for(int i=1; i<=n; i++) printf("%d ",a[i]); puts(" a");

	int tot=0, li[5];
	for(int i=1; i<=n; i+=2) 
		if(a[i]+1 != a[i+1]) {li[++tot]=i; if(tot>2) return;}

	int x=li[1], y=li[2];
	if(tot==2) {
		swap(a[x], a[y]);
		if(check(a, x, y)) memcpy(b, a, sizeof(int)*(n+1)), ready(b, n>>1), dfs(d+1, n>>1, now+1); 
		swap(a[x], a[y]);

		swap(a[x], a[y+1]);
		if(check(a, x, y)) memcpy(b, a, sizeof(int)*(n+1)), ready(b, n>>1), dfs(d+1, n>>1, now+1); 
		swap(a[x], a[y+1]);

		swap(a[x+1], a[y]);
		if(check(a, x, y)) memcpy(b, a, sizeof(int)*(n+1)), ready(b, n>>1), dfs(d+1, n>>1, now+1); 
		swap(a[x+1], a[y]);

		swap(a[x+1], a[y+1]);
		if(check(a, x, y)) memcpy(b, a, sizeof(int)*(n+1)), ready(b, n>>1), dfs(d+1, n>>1, now+1); 
		swap(a[x+1], a[y+1]);
	} else if(tot==0) memcpy(b, a, sizeof(int)*(n+1)), ready(b, n>>1), dfs(d+1, n>>1, now);
	else if(tot==1) swap(a[x], a[x+1]), memcpy(b, a, sizeof(int)*(n+1)), ready(b, n>>1), dfs(d+1, n>>1, now+1);
}
int main() {
	freopen("in","r",stdin);
	bin=read(); n=1<<bin;
	fac[0]=1;
	for(int i=1; i<=bin; i++) fac[i]=fac[i-1]*i;
	for(int i=1; i<=n; i++) t[0][i]=read();
	dfs(0, n, 0);
	printf("%lld", ans);
}

posted @ 2017-04-06 21:26  Candy?  阅读(285)  评论(0编辑  收藏  举报