bzoj3990: [SDOI2015]排序

来源:互联网 发布:飞歌导航 高德 端口 编辑:程序博客网 时间:2024/05/22 04:46

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

一个整数表示答案

Sample Input

3

7 8 5 6 1 2 4 3
Sample Output

6

HINT

100%的数据, 1<=N<=12.

题意

自己看

题解

很容易知道,顺序是没有关系的,最后组合一下就好了
然后呢,我们知道,一般移动方案是很少的,因为你每一堆只能移动一次
其实就是恶心的暴力搜索题。。
CODE

#include<cstdio>#include<cstdlib>#include<algorithm>#include<iostream>#include<cstring>using namespace std;const int N=1<<13;int n;int s[N];inline int read(){    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 ans=0;int tt[15];void SWAP(int a,int b,int x){    for (int u=0;u<x;u++)        swap(s[a+u],s[b+u]);}void dfs (int x,int y)//我们管理的范围{/*  printf("%d\n",x);    for (int u=1;u<=n;u++) printf("%d ",s[u]);    system("pause");*/    int L[N],R[N];//最左位和最右位    if (x==n)    {        ans+=tt[y];        return ;    }    int cnt=0;    for (int u=1;u<=n;u+=x)        R[cnt]=u-1,L[++cnt]=u;    R[cnt]=n;    int tf=0;    int X=-1,Y=-1;    for (int u=1;u<=cnt;u+=2)        if (s[R[u]]+1!=s[L[u+1]])        {            if (tf==0)  X=u;            else if (tf==1) Y=u;            else return ;            tf++;        }    if (tf==0) dfs(x*2,y);    //现在知道X和Y有问题    if (Y==-1)    {        if (s[R[X+1]]+1==s[L[X]])        {            SWAP(L[X+1],L[X],x);            dfs(x*2,y+1);            SWAP(L[X+1],L[X],x);        }        return ;    }    if (s[R[X]]+1==s[L[Y+1]]&&s[R[Y]]+1==s[L[X+1]])//这个是X和Y交换     {        SWAP(L[X],L[Y],x);        dfs(x*2,y+1);        SWAP(L[X],L[Y],x);    }    if (s[R[Y]]+1==s[L[X]]&&s[R[Y+1]]+1==s[L[X+1]])//这个是X和Y+1交换     {        SWAP(L[X],L[Y+1],x);        dfs(x*2,y+1);        SWAP(L[X],L[Y+1],x);    }    if (s[R[X]]+1==s[L[Y]]&&s[R[X+1]]+1==s[L[Y+1]])//这个是X+1和Y交换     {        SWAP(L[X+1],L[Y],x);        dfs(x*2,y+1);        SWAP(L[X+1],L[Y],x);    }    if (s[R[X]]+1==s[L[Y+1]]&&s[R[Y]]+1==s[L[X+1]])//这个是X+1和Y+1交换     {        SWAP(L[X+1],L[Y+1],x);        dfs(x*2,y+1);        SWAP(L[X+1],L[Y+1],x);    }}int main(){    scanf("%d",&n);n=1<<n;    for (int u=1;u<=n;u++) scanf("%d",&s[u]);    tt[0]=1;    for (int u=1;u<=14;u++) tt[u]=tt[u-1]*u;    dfs(1,0);//深度     printf("%d\n",ans);    return 0;}