• 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
    ",Ans);
    }
  • 相关阅读:
    17963 完美数
    17086 字典序的全排列
    17082 两个有序数序列中找第k小(优先做)
    11087 统计逆序对(优先做)
    8594 有重复元素的排列问题(优先做)
    11076 浮点数的分数表达(优先做)
    9715 相邻最大矩形面积
    剑指offer----替换空格
    [IIS][ASP.NET]“拒绝访问临时目录”的解决方法
    windows 2003端口80system进程占用的情况
  • 原文地址:https://www.cnblogs.com/applejxt/p/4442532.html
Copyright © 2020-2023  润新知