• Codeforces 629C Famil Door and Brackets(DP)


    题目大概说给一个长m的括号序列s,要在其前面和后面添加括号使其变为合法的长度n的括号序列,p+s+q,问有几种方式。(合法的括号序列当且仅当左括号总数等于右括号总数且任何一个前缀左括号数大于等于右括号数)

    我这么想的:n-m<=2000,因而可以dp计算p和q的方案数,同时在各个地方加入s进行转移。

    • dp[0/1][i][j]表示s没有/有加入时,p和q前i个括号已经确定且还有j的左括号还没匹配的方案数
    • 注意到任何前缀的左括号都是大于等于右括号的,因此j这一维不会小于0。
    • 那么转移,我用我为人人转移,就是:
    • 尾巴加上左括号:

    d[0][i+1][j+1]+=d[0][i][j]

    • 尾巴加上右括号:

    d[0][i+1][j-1]+=d[0][i][j]

    • 尾巴加上左括号和s:

    d[1][i+1][j+1+cnt]+=d[0][i][j](cnt=s中左括号数-右括号数)

    • 尾巴加上右括号和s:

    d[1][i+1][j-1+cnt]+=d[0][i][j](cnt=s中左括号数-右括号数)

    • 从已经加上s的转移:

    d[1][i+1][j+1]+=d[1][i][j]

    d[1][i+1][j-1]+=d[1][i][j]

    这些转移前提是要合法。合法情况还有一点要注意的是,s不一定都能随便放到p和q任何一个地方的,因为可能出现p+s的序列不合法,即p+s序列中存在前缀左括号数小于右括号数,所以还要用j这一维的值与cnt的值比较。

    看了下题解,它的做法是求出dp[i][j],这个dp[i][j]既是前缀方案数又是后缀方案数,因为后缀相当于前缀反过来,其右括号数目大于等于左括号数目。通过枚举p的i和j来确定q,而q是后缀,而二者的方案数乘积为答案的一部分贡献。

    另外这一题写完后直接提交差点点1A了,不过感觉还不错,难得考虑全面。。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 int d[2][2222][4444];
     6 int main(){
     7     char ch;
     8     int n,m,cnt=0,precnt=0;
     9     scanf("%d%d",&n,&m);
    10     int N=n-m;
    11     for(int i=0; i<m; ++i){
    12         scanf(" %c",&ch);
    13         if(ch=='(') ++cnt;
    14         else --cnt;
    15         precnt=min(precnt,cnt);
    16     }
    17     d[0][0][0]=1;
    18     if(0<=cnt&& cnt<=2*N && precnt==0) d[1][0][cnt]=1;
    19     for(int i=0; i<N; ++i){
    20         for(int j=0; j<=2*N; ++j){
    21             if(j+1<=2*N){
    22                 d[0][i+1][j+1]+=d[0][i][j];
    23                 d[0][i+1][j+1]%=1000000007;
    24             }
    25             if(j-1>=0){
    26                 d[0][i+1][j-1]+=d[0][i][j];
    27                 d[0][i+1][j-1]%=1000000007;
    28             }
    29             if(j+1<=2*N){
    30                 d[1][i+1][j+1]+=d[1][i][j];
    31                 d[1][i+1][j+1]%=1000000007;
    32             }
    33             if(j-1>=0){
    34                 d[1][i+1][j-1]+=d[1][i][j];
    35                 d[1][i+1][j-1]%=1000000007;
    36             }
    37             if(0<=j+1+cnt && j+1+cnt<=2*N && j+1+precnt>=0){
    38                 d[1][i+1][j+1+cnt]+=d[0][i][j];
    39                 d[1][i+1][j+1+cnt]%=1000000007;
    40             }
    41             if(0<=j-1+cnt && j-1+cnt<=2*N && j-1+precnt>=0){
    42                 d[1][i+1][j-1+cnt]+=d[0][i][j];
    43                 d[1][i+1][j-1+cnt]%=1000000007;
    44             }
    45         }
    46     }
    47     printf("%d",d[1][N][0]);
    48     return 0;
    49 }
  • 相关阅读:
    python基础练习:
    py+selenium切换到新弹出窗口通用方法
    Python 异常处理
    验证码自动化认证部分,可能由于分辨率导致截图不正确
    基于Tesseract的OCR图像识别
    Spark相关知识
    Hive和数据库除了拥有类似的查询语言,再无类似之处;关系型数据库和非关系型数据库的优缺点
    sed替换^A(01),02,03等特殊字符
    Python操作adb命令脚本
    python从放弃到放弃
  • 原文地址:https://www.cnblogs.com/WABoss/p/5682098.html
Copyright © 2020-2023  润新知