BZOJ 3990 [SDOI2015]排序 ——搜索
【题目分析】
可以发现,操作的先后顺序是不影响结果的,那么答案就是n!的和。
可以从小的步骤开始搜索,使得每一个当前最小的块都是上升的数列,然后看看是否可行即可。
复杂度好像是4^n
【代码】(哪里写挂了,意会一下就好了)
#include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <map> #include <set> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define maxn 5005 #define ll long long #define mlog 15 #define inf 0x3f3f3f3f #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) void Finout() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); #endif } int Getint() { int x=0,f=1; char ch=getchar(); while (ch<'0'||ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } int a[mlog][maxn],b[maxn],n,cnt=0,s; ll ans=0; ll fac[mlog]; void solve(int now,int n) { if (n==1) { ans+=fac[s]; return ; } int cnt=0; int pos1=0,pos2=0; for (int i=1;i<=n;i+=2) { if (a[now][i]>a[now][i+1]) { cnt++; if (!pos1) pos1=i; else pos2=i; } if (cnt>2) return ; } if (cnt==0) { for (int i=1;i<=n/2;++i) a[now+1][i]=(a[now][i*2-1]+1)/2; solve(now+1,n/2); } else { if (cnt==1) { swap(a[now][pos1],a[now][pos1+1]); s++; for (int i=1;i<=n/2;++i) a[now+1][i]=(a[now][i*2-1]+1)/2; solve(now+1,n/2); s--; swap(a[now][pos1],a[now][pos1+1]); } else { swap(a[now][pos1],a[now][pos2]); if (a[now][pos1]<a[now][pos1+1]&&a[now][pos2]<a[now][pos2+1]) { s++; for (int i=1;i<=n/2;++i) a[now+1][i]=(a[now][i*2-1]+1)/2; solve(now+1,n/2); s--; } swap(a[now][pos1],a[now][pos2]); swap(a[now][pos1+1],a[now][pos2]); if (a[now][pos1]<a[now][pos1+1]&&a[now][pos2]<a[now][pos2+1]) { s++; for (int i=1;i<=n/2;++i) a[now+1][i]=(a[now][i*2-1]+1)/2; solve(now+1,n/2); s--; } swap(a[now][pos1+1],a[now][pos2]); swap(a[now][pos1],a[now][pos2+1]); if (a[now][pos1]<a[now][pos1+1]&&a[now][pos2]<a[now][pos2+1]) { s++; for (int i=1;i<=n/2;++i) a[now+1][i]=(a[now][i*2-1]+1)/2; solve(now+1,n/2); s--; } swap(a[now][pos1],a[now][pos2+1]); swap(a[now][pos1+1],a[now][pos2+1]); if (a[now][pos1]<a[now][pos1+1]&&a[now][pos2]<a[now][pos2+1]) { s++; for (int i=1;i<=n/2;++i) a[now+1][i]=(a[now][i*2-1]+1)/2; solve(now+1,n/2); s--; } swap(a[now][pos1+1],a[now][pos2+1]); } } return ; } int main() { Finout(); n=Getint(); n=1<<n; fac[0]=1; F(i,1,12) fac[i]=fac[i-1]*i; F(i,1,n) a[1][i]=Getint(); solve(1,n); cout<<ans<<endl; }