• BZOJ3990:[SDOI2015]排序——题解


    https://www.lydsy.com/JudgeOnline/problem.php?id=3990

    小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].

    考虑暴力怎么写……不会啊。

    我们能知道实际上操作顺序不影响结果,于是我们大可以从1~n枚举操作做。

    因为最终变得有序,所以我们可以对于每一“大块”查询是否已经排好序了,如果没排好,就说明这一“大块”里的两小块肯定是放错位置的。

    如果这样的小块<=4的话我们还好办,显然是前一“大块”的其中一“小块”和后一“大块”的其中一“小块”交换位置。

    如果<=2那么就这两块交换就行了。

    如果>4我们就处理不了了。

    #include<map>
    #include<cmath>
    #include<stack>
    #include<queue>
    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=1<<13;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    int n,m,a[N];
    ll jc[N],ans;
    bool pan(int l,int r){
        for(int i=l;i<r;i++)
        if(a[i]+1!=a[i+1])return 0;
        return 1;
    }
    void mdy(int l,int r,int k){
        for(int i=l,j=r;i<l+(1<<k);i++,j++)
        swap(a[i],a[j]);
    }
    void dfs(int l,int num){
        if(l>n){
        ans+=jc[num];
        return;
        }
        int tmp[4],tot=0;
        for(int i=1;i<=m;i+=(1<<l))
        if(!pan(i,i+(1<<l)-1)){
            tmp[++tot]=i;
            if(tot>2)return;
        }
        if(!tot){dfs(l+1,num);return;}
        else if(tot==1){
        mdy(tmp[1],tmp[1]+(1<<l-1),l-1);
        if(pan(tmp[1],tmp[1]+(1<<l-1)))dfs(l+1,num+1);
        mdy(tmp[1],tmp[1]+(1<<l-1),l-1);
        }else{
        for(int i=0;i<=1;i++)
            for(int j=0;j<=1;j++){
            mdy(tmp[1]+(i<<(l-1)),tmp[2]+(j<<(l-1)),l-1);
            if(pan(tmp[1],tmp[1]+(1<<l-1))&&
                pan(tmp[2],tmp[2]+(1<<l-1)))dfs(l+1,num+1);
            mdy(tmp[1]+(i<<(l-1)),tmp[2]+(j<<(l-1)),l-1);
            }
        }
    }
    int main(){
        n=read(),m=1<<n;
        jc[0]=1;for(int i=1;i<=n;i++)jc[i]=jc[i-1]*i;
        for(int i=1;i<=m;i++)a[i]=read();
        dfs(1,0);
        printf("%lld
    ",ans);
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    如何理解css3 -webkit-animation-fill-mode属性值为both时的使用方法
    关于对canvas.beginPath()的理解
    [cf10E]Greedy Change
    [atAGC055B]ABC Supremacy
    [loj6734]图上的游戏
    [gym102412D]The Jump from Height of Self-importance to Height of IQ Level
    [Aizu1410]Draw in Straight Lines
    [Aizu2993]Invariant Tree
    [zoj3990]Tree Equation
    [hdu6326]Monster Hunter
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9202312.html
Copyright © 2020-2023  润新知