zoukankan      html  css  js  c++  java
  • 【洛谷1044】栈

    原题:

     n<=18

    性质 1 :

    观察发现,栈里的数的顺序一定等同它们在原序列的顺序

    这个易证

    这道题的原序列是递增的,所以栈里的数列也是递增的

    因此可以设计状态,f [ i ] [ j ] 表示原序列还有 i 个数,栈内数的集合为 j( j 是二进制压位数)的出栈数列方案数

    n 很小,二进制压位就可以做了

    但是实际上这道题还有更简单的做法,f [ i ] [ j ] 表示 i 个数没进过栈,j 个数在栈里的方案数

    这个做法正确是因为

    性质 2 :

    对于同一个初始序列,且初始序列中的数各不相同,压栈弹栈的操作序列与最终的结果序列是意义对应的

    即不存在两种不同的操作序列,使得它们排序的结果相同

    证明思路:

    对于一个操作序列 s ,以及一个出栈序列 t ,尝试找出另一个操作序列,使得出栈序列等于 t

    对于 t 中第一个数,由于本题中只能栈前进栈后出,所以若想让出栈序列第一个数和 t 的第一个数相等

    必须执行和 s 对应部分相同的操作

    剩余部分容易由归纳法类似证明

    第三种做法是使用卡塔兰数

    洛谷题解第一个讲得很好很清楚,我就不再造轮子了

     其实是之前根本不会卡塔兰数,这里学习一个 =。=

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 int f[19][262144];
     5 int n;
     6 int main(){
     7     cin>>n;
     8     f[0][0]=1;
     9     for(int i=0;i<=n;++i)for(int j=(1<<n)-1;j>=0;--j)if(f[i][j]){
    10         if(i!=n){
    11             f[i+1][j|(1<<i)]+=f[i][j];
    12         }
    13         if(j!=0){
    14             int k=0;
    15             for(k=0;k<n;++k)if(j&(1<<k))  break;
    16             f[i][j^(1<<k)]+=f[i][j];
    17         }
    18     }
    19     cout<<f[n][0]<<endl;
    20     return 0;
    21 }
    View Code

    UPD:

    2020.9.26发现以前写得有点小问题,放一下更严谨的给洛谷写的ppt里关于这题的解法

     

     

  • 相关阅读:
    WinRAR v5.90中文正式32&64位整合安装版
    WIN10永久激活工具 HWIDGEN
    Adobe2020套装激活工具
    keka 1.1.26-压缩工具
    python文件和目录操作方法大全(含实例)
    如何使公网能够访问本地web服务器?
    网线那根正极那根负极
    HPUX 大文件系统扩容
    LESS详解之函数(四)
    Win7 安装Apache 2.2.4报错:<OS 5>拒绝访问. :Failed to open the WinNT service manager
  • 原文地址:https://www.cnblogs.com/cdcq/p/12633888.html
Copyright © 2011-2022 走看看