• BZOJ 3990 排序


    题目描述

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


    【输入格式】

    第一行,一个整数N。

    第二行,2N个整数,A[1]、A[2]…A[2N]。

     


     

    【输出格式】

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

     


     

    【样例输入】

    3

    7 8 5 6 1 2 4 3


    【样例输出】

    6


     

    【数据规模和约定】

    对于30%的数据,1<=N<=4

    对于全部的数据,1<=N<=12。

     


    题解:

    15%算法:输出阶乘。

    这个代码就不发了,应该没有人不会打阶乘。

    这是一个非常迷的东西,为什么输出阶乘能得分呢?首先我们发现,如果已经找到了一种交换方法,那么我们任意交换其中的操作,这样也能得到最终的序列

    证明的话,一下摘自某大佬博客:

     

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

     

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

     

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

     

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

     

    所以会有一个阶乘。如果你看出来了,这很方便你qj测试点

     

    当然我们练习时需要打正解,下面是100%算法:

    上面我们已经知道了这条性质,那么下面的问题就是如何找到这样的一组操作

    我们从短的区间2i枚举,如果有一段长度为2i+1的序列并不是公差为1的递增区间,我们就记录一下,

    如果这样的区间大于两段,直接return就好。

    如果没有。。。你啥都做不了,接着搜下一段长度的区间

    如果只有一段,段内直接交换即可

    如果有两段,那么需要判断4种情况进行dfs

    这四种情况是:前一段的前一段和后一段的前一段,前一段的后一段和后一段的前一段,前一段的前一段和后一段的后一段,前一段的后一段和后一段的前一段。

    感谢barca友情提供

    废话不说,上代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #define ll long long
     5 using namespace std;
     6 ll n,a[1<<13],js[13],m,ans=0;
     7 bool judge(ll l,ll r){
     8     for(ll i=l;i<r;i++)
     9         if(a[i+1]!=a[i]+1)
    10             return false;
    11     return true;
    12 }
    13 void change(ll x,ll y,ll l){
    14     for(ll i=x,j=y;l;l--,i++,j++)
    15         swap(a[i],a[j]);
    16 }
    17 void dfs(ll x,ll y){
    18     if(x==n){
    19         ans+=js[y];
    20         return ;
    21     }
    22     ll sum=0,temp[5],p=1<<x+1;
    23     for(ll i=1;i<=m;i+=p){
    24         if(judge(i,i+p-1)) continue;
    25         temp[++sum]=i;
    26         if(sum==3) return ;
    27     }
    28     if(sum>3) return ;
    29     if(!sum){
    30         dfs(x+1,y);
    31         return ;
    32     }
    33     if(sum==1){
    34         change(temp[sum],temp[sum]+(1<<x),1<<x);
    35         if(judge(temp[sum],temp[sum]+p-1)) dfs(x+1,y+1);
    36         change(temp[sum],temp[sum]+(1<<x),1<<x);
    37         return ;
    38     }
    39     if(sum==2){
    40         change(temp[sum-1],temp[sum],1<<x);
    41         if(judge(temp[sum-1],temp[sum-1]+p-1)&&judge(temp[sum],temp[sum]+p-1))
    42             dfs(x+1,y+1);
    43         change(temp[sum-1],temp[sum],1<<x);
    44 
    45         change(temp[sum-1],temp[sum]+(1<<x),1<<x);
    46         if(judge(temp[sum-1],temp[sum-1]+p-1)&&judge(temp[sum],temp[sum]+p-1))
    47         dfs(x+1,y+1);
    48         change(temp[sum-1],temp[sum]+(1<<x),1<<x);
    49 
    50         change(temp[sum-1]+(1<<x),temp[sum],1<<x);
    51         if(judge(temp[sum-1],temp[sum-1]+p-1)&&judge(temp[sum],temp[sum]+p-1))
    52             dfs(x+1,y+1);
    53         change(temp[sum-1]+(1<<x),temp[sum],1<<x);
    54 
    55         change(temp[sum-1]+(1<<x),temp[sum]+(1<<x),1<<x);
    56         if(judge(temp[sum-1],temp[sum-1]+p-1)&&judge(temp[sum],temp[sum]+p-1))
    57             dfs(x+1,y+1);
    58         change(temp[sum-1]+(1<<x),temp[sum]+(1<<x),1<<x);
    59     }
    60 }
    61 int main(){
    62     scanf("%lld",&n);
    63     js[0]=1,m=1<<n;
    64     for(ll i=1;i<=n;i++)
    65         js[i]=js[i-1]*i;
    66     for(ll i=1;i<=m;i++)
    67         scanf("%lld",&a[i]);
    68     dfs(0,0);
    69     printf("%lld
    ",ans);
    70     return 0;
    71 }
    View Code
  • 相关阅读:
    Emit介绍【转】
    在.NET中使用反射实现简易插件机制【转】
    RabbitMQ笔记-Qos与消息应答
    Http级别缓存助手类(ASP.Net Core)
    实现一个迷你IOC容器
    使用CMake在Windows环境下的VS2019中配置openCV
    如何在Visual Studio 2019中启动并配置一个使用pyTorch的C++项目(Windows系统,CMAKE项目)
    windows环境下使用python中tensorflow的tensorboard功能无法创建指定路径的问题
    使用python的selenium库自动填写网页(疫情每日一报)
    十进制转换二进制toBinaryString源码分析
  • 原文地址:https://www.cnblogs.com/Juve/p/11158274.html
Copyright © 2020-2023  润新知