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;
}

  

posted @ 2017-01-10 22:57  SfailSth  阅读(120)  评论(0编辑  收藏  举报