bzoj3990[SDOI2015]排序
http://www.lydsy.com/JudgeOnline/problem.php?id=3990
DFS
好吧,表示不会做。
发现对于这些搜索的题我比较弱,看来需要加强一下。
回归正题。
我们发现对于一个操作方案(不妨记操作数为$cnt$),我们任意改变操作的顺序,总可以满足条件。
根据最小表示法的原理,我们规定按照编号从小到大进行操作,如果可行,那么$ans+=cnt!$
假设我们做到第$i$个操作,此时对于第$1$到第$i-1$个操作,我们已经知道了各个操作是否用到;并且我们保证:如果序列划分成$2^{N-i+1}$个长度为$2^{i-1}$的段,那么每一段的数字都是递增且连续的。
那么我们在做第做到第$i$个操作时,我们要保证:如果序列划分成$2^{N-i}$个长度为$2^{i}$的段,那么每一段的数字都是递增且连续的。
怎么保证呢?
我们将序列划分成$2^{N-i}$个长度为$2^{i}$的段,看看每一段是否是递增且连续的。
如果有多于2个长度为$2^{i}$的段不是递增且连续的,那么肯定是没救的。
如果有1个长度为$2^{i}$的段不是递增且连续的,我们一定能将这个长度为$2^{i}$的段平均分成2个长度为$2^{i-1}$的段,并且这2个长度为$2^{i-1}$的段一定是递增且连续的(为什么?因为我们保证如果序列划分成$2^{N-i+1}$个长度为$2^{i-1}$的段,那么每一段的数字都是递增且连续的)
那么交换这两段并判断是否可行,继续搜索。
如果有2个长度为$2^{i}$的段不是递增且连续的,类似得,我们分别将2个长度为$2^{i}$的段平均分成2个长度为$2^{i-1}$的段,总共有4个长度为$2^{i-1}$的段,有4种交换方法,交换并判断是否可行后继续搜索即可。
#include<cstdio> #include<cstdlib> #include<iostream> #include<fstream> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<queue> #include<stack> #include<map> #include<utility> #include<set> #include<bitset> #include<vector> #include<functional> #include<deque> #include<cctype> #include<climits> #include<complex> //#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj using namespace std; typedef long long LL; typedef double DB; typedef pair<int,int> PII; typedef complex<DB> CP; #define mmst(a,v) memset(a,v,sizeof(a)) #define mmcy(a,b) memcpy(a,b,sizeof(a)) #define fill(a,l,r,v) fill(a+l,a+r+1,v) #define re(i,a,b) for(i=(a);i<=(b);i++) #define red(i,a,b) for(i=(a);i>=(b);i--) #define ire(i,x) for(typedef(x.begin()) i=x.begin();i!=x.end();i++) #define fi first #define se second #define m_p(a,b) make_pair(a,b) #define p_b(a) push_back(a) #define SF scanf #define PF printf #define two(k) (1<<(k)) template<class T>inline T sqr(T x){return x*x;} template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;} template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;} const DB EPS=1e-9; inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;} const DB Pi=acos(-1.0); inline int gint() { int res=0;bool neg=0;char z; for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar()); if(z==EOF)return 0; if(z=='-'){neg=1;z=getchar();} for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar()); return (neg)?-res:res; } inline LL gll() { LL res=0;bool neg=0;char z; for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar()); if(z==EOF)return 0; if(z=='-'){neg=1;z=getchar();} for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar()); return (neg)?-res:res; } const int maxN=12; int N; int fac[maxN+10]; vector<int>A; int ans; inline int check(vector<int> &A,int l,int r) { int i; re(i,l+1,r)if(A[i]!=A[i-1]+1)return 0; return 1; } inline void SWAP(vector<int> &A,int x,int y,int len) { int i; re(i,1,len)swap(A[x+i-1],A[y+i-1]); } inline void DFS(vector<int> A,int k,int cnt) { if(k==N){ans+=fac[cnt];return;} int i,b[5],tot=0; for(i=1;i<=two(N);i+=two(k+1)) if(!check(A,i,i+two(k+1)-1)) { if(tot==4)return; b[++tot]=i,b[++tot]=i+two(k); } if(tot==0) { DFS(A,k+1,cnt); return; } vector<int>B; if(tot==2) { if(A[b[2]]+two(k)==A[b[1]]) { B=A; SWAP(B,b[1],b[2],two(k)); DFS(B,k+1,cnt+1); } return; } if(tot==4) { if(A[b[3]]+two(k)==A[b[2]] && A[b[1]]+two(k)==A[b[4]]) { B=A; SWAP(B,b[1],b[3],two(k)); DFS(B,k+1,cnt+1); } if(A[b[4]]+two(k)==A[b[2]] && A[b[3]]+two(k)==A[b[1]]) { B=A; SWAP(B,b[1],b[4],two(k)); DFS(B,k+1,cnt+1); } if(A[b[1]]+two(k)==A[b[3]] && A[b[2]]+two(k)==A[b[4]]) { B=A; SWAP(B,b[2],b[3],two(k)); DFS(B,k+1,cnt+1); } if(A[b[1]]+two(k)==A[b[4]] && A[b[3]]+two(k)==A[b[2]]) { B=A; SWAP(B,b[2],b[4],two(k)); DFS(B,k+1,cnt+1); } return; } } int main() { freopen("sort.in","r",stdin); freopen("sort.out","w",stdout); int i; N=gint(); fac[0]=1;re(i,1,N)fac[i]=fac[i-1]*i; A.resize(two(N)+1);re(i,1,two(N))A[i]=gint(); DFS(A,0,0); cout<<ans<<endl; return 0; }