SDOI2015 排序

Description

小A有一个1~2N的排列A[1..2N],他希望将数组A从小到大排序。小A可以执行的操作有N种,每种操作最多可以执行一次。对于所有的i(1<=i<=N),第i种操作为:将序列从左到右划分成2N-i+1段,每段恰好包含2i-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。
第二行,2N个整数,A[1]、A[2]…A[2N]。

Output

一行,一个整数,表示可以将数组A从小到大排序的不同的操作序列的个数。
 

Sample Input

3
7 8 5 6 1 2 4 3

Sample Output

6
 

Data Constraint

对于30%的数据,1<=N<=4;
对于全部的数据,1<=N<=12。
 
解法:
先打个暴力,可以发现一个重要结论!
对于一个操作序列,如果它是合法的,那么它的全排列都是合法的。所以我们操作区间从小到大进行操作。
对于每次操作,假如我们交换的序列长度为T,那么我们将整个序列按每段2T分成多段,对于每一段,由于我们是从小到大操作,之后的操作至少都是2T的整段交换,所以这2T个数内部的相对关系在以后不会发生改变。如果要使序列合法,在这次操作后,我们至少要使每2T个数是连续递增的。
对于每次操作,我们先扫一遍,看有多少个2T的区间是不合法的。
如果不合法的区间数大于2,那么无解
如果没有不合法的区间,那么不需要进行这个长度的操作,直接跳到下一层。
如果区间数为1或2,暴力修改交换看是否能达成合法状态。(1则前后交换,2则2个区间之间进行交换,有4种方案)
你写的丑一点也是O(4^n),可以通过本题
 
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>

using namespace std;
typedef long long ll;
ll jc[13],Ans;
int a[4201];
int n,ws,i;

bool Can()
{
    int i;
    for(i=1;i<=n;i++)if(a[i]!=i)return false;
    return true;
}

bool check(int x,int i)
{
    int nxt,lst;
    lst=(i-1)*x+x/2;
    nxt=lst+1;
    if(a[nxt]!=a[lst]+1)return false;
    else return true;
}

void dfs(int dep,int kf)
{
    bool pp;
    int dif[3];
    int one,num,chk,tx,ty,i,j,l;
    if(Can()){
        Ans+=jc[kf];
        return;
    }    
    if(dep==ws+1)return;
    one=1<<dep;
    num=n/one;
    chk=0;
    for(i=1;i<=num;i++)if(check(one,i)==false){
        chk++;
        if(chk>2)return;
        dif[chk]=i;
    }
    if(chk==0)dfs(dep+1,kf);
    if(chk>2)return;
    if(chk==1){
        tx=(dif[chk]-1)*one+1;
        ty=tx+one/2;
        for(i=1;i<=one/2;i++)swap(a[tx+i-1],a[ty+i-1]);
        dfs(dep+1,kf+1);
        for(i=1;i<=one/2;i++)swap(a[tx+i-1],a[ty+i-1]);
    }
    if(chk==2){
        for(i=1;i<=2;i++)
            for(j=1;j<=2;j++){
                if(i==1)tx=(dif[1]-1)*one+1;
                else tx=(dif[1]-1)*one+1+one/2;
                if(j==1)ty=(dif[2]-1)*one+1;
                else ty=(dif[2]-1)*one+1+one/2;
                for(l=1;l<=one/2;l++)swap(a[tx+l-1],a[ty+l-1]);
                pp=check(one,dif[1])&check(one,dif[2]);
                if(pp)dfs(dep+1,kf+1);
                for(l=1;l<=one/2;l++)swap(a[tx+l-1],a[ty+l-1]);
            }
    }
}

int main()
{
    scanf("%d",&ws);
    jc[0]=1;
    for(i=1;i<=ws;i++)jc[i]=jc[i-1]*i;
    n=1<<ws;
    for(i=1;i<=n;i++)scanf("%d",&a[i]);
    dfs(1,0);
    printf("%lld\n",Ans);
}

 

posted on 2015-04-20 20:25  razorjxt  阅读(173)  评论(0编辑  收藏  举报