• BZOJ3990 排序(sort)


    排序(sort)

    题目描述

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

    n12 


    solution

    我们假设已知一个合法的操作序列。

    那么这个序列的全排列也是合法的。

    证明嘛。大概意会一下

    假设我现在第一次换a,b ,第二次换c,d 且a比c长

    那么cd完全被包含和完全无交集肯定不影响。

    现在假设c被a包含,d和b分开

    那么可以把操作c~d改为操作 (c在b种对应位置)~d

    好了,那么还剩下怎么验证合法序列

    我们从短区间开始枚举,假设当前在2^n。

    那么如果有一段长度为2^(n+1)的区间不是递增的,就记下来。

    这里的递增指相差1的递增 如123合法 135就不行

    然后分类。

    如果段数>=3 就是不合法的(后面也不可能进行这么细微的调整了)

    如果=2可以取第一段的和第二段的某一段换,4种情况

    如果=1 直接段内换

    =0不操作 也一定不能操作

    注意递归变量一定要开局部 局部!!!

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    int n,N,s[1<<13],fac[22],ans;
    bool pd(int l,int r){
        bool fl=1;
        for(int i=l;i<r;i++){
            if(s[i]+1!=s[i+1]){fl=0;break;}
        }
        return fl;
    }
    void work(int x,int y,int l){
        for(int i=x,j=y;l;l--,i++,j++)swap(s[i],s[j]);
    }
    void dfs(int k,int op,int ff){
        if(k==n){
            ans+=fac[op];return;
        }
        int now=(1<<k+1),sum=0,nn=(1<<k),b[5];
        for(int j=1;j<=N;j+=now){
            if(!pd(j,j+now-1)){
                b[++sum]=j; 
                if(sum==3)return; 
            }
        }
        if(sum==0){dfs(k+1,op,-1);return;}
        if(sum>3)return;
        if(sum==1){
            work(b[1],b[1]+nn,nn);
            if(pd(b[1],b[1]+now-1))dfs(k+1,op+1,0);
            work(b[1],b[1]+nn,nn);
            return;
        }
        if(sum==2){
        work(b[1],b[2],nn);
        if(pd(b[1],b[1]+now-1)&&pd(b[2],b[2]+now-1))dfs(k+1,op+1,1);
        work(b[1],b[2],nn);
         
        work(b[1],b[2]+nn,nn);
        if(pd(b[1],b[1]+now-1)&&pd(b[2],b[2]+now-1))dfs(k+1,op+1,2);
        work(b[1],b[2]+nn,nn);
         
        work(b[1]+nn,b[2],nn);
        if(pd(b[1],b[1]+now-1)&&pd(b[2],b[2]+now-1))dfs(k+1,op+1,3);
        work(b[1]+nn,b[2],nn);
         
        work(b[1]+nn,b[2]+nn,nn);
        if(pd(b[1],b[1]+now-1)&&pd(b[2],b[2]+now-1))dfs(k+1,op+1,4);
        work(b[1]+nn,b[2]+nn,nn);
         
        }
    }
    int main()
    {
        cin>>n;N=(1<<n);
        for(int i=1;i<=N;i++)scanf("%d",&s[i]);
        fac[0]=1;for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i;
        dfs(0,0,-2);
        cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    将Nginx添加到windows服务中
    springboot使用redis管理session
    GIT常用命令
    阻止360、谷歌浏览器表单自动填充
    谈谈对Spring IOC的理解
    同一个Nginx服务器同一端口配置多个代理服务
    LeetCode 653. Two Sum IV
    109. Convert Sorted List to Binary Search Tree(根据有序链表构造平衡的二叉查找树)
    108. Convert Sorted Array to Binary Search Tree(从有序数组中构造平衡的BST)
    LeetCode 236. Lowest Common Ancestor of a Binary Tree(二叉树求两点LCA)
  • 原文地址:https://www.cnblogs.com/liankewei/p/10358758.html
Copyright © 2020-2023  润新知