Codeforces Round #501 F. Bracket Substring 思路+dp+KMP 详解

26 篇文章 0 订阅
24 篇文章 0 订阅

题意:

给定n和一个括号序列 t,问:一个长度为2*n 的括号序列 s 的种类数,要求 t 是 s 的子串,s是平衡括号序列;

思路:

这个题算是 BZOJ - 1009: [HNOI2008]GT考试 dp+KMP https://blog.csdn.net/xiang_6/article/details/81434904

的简化版本; 解释一下这个题:

 

首先我们不考虑是否是平衡括号序列这个要求,如果只是要求 包含 t 的 s 的种类的话,我们可以

dp[i][j] 表示 当匹配到 s 串的第 i 个字符的时候,恰好匹配到 t 串的第 j 个字符,并且此时 s 串包含 j 个字符的后缀恰好是 t 串的前缀;这是dp[i][j] 就是上述条件下的种类数,再看状态转移

当我们要继续匹配 s 串第 i+1个字符时,对于本题,只有 ‘(’ ,‘)’ 两种情况,然后我们假设加上第 i+1个字符后,恰好匹配到了 t 串的第x个位置(这里的匹配是满足上述dp[][] 的定义的匹配),这样的话,dp[i][j] 就为 dp[i+1][x] 做出来贡献,

所以转移方程就是 dp[i+1][x] += dp[i][j] 这里的 x 由当前位置 j 和新加入的字符决定;这个 x 可以用KMP快速实现得到;

需要注意:当dp[i][j] 中 j = len(t 串长度) 时,无论添加什么字符,我们都仍然往 dp[i+1][len] 转移

 

然后我们考虑 s 是否是平衡括号序列的问题:

只需要再添加一维,令 dp[i][j][k], 前两维还是上述的 dp[i][j],,第三维表示当前括号序列中,除去平衡括号外,左括号多出来的数目为k,因为从左往右添加括号,右括号不能超过左括号,所以 k >=0, 转移方程改为:

当新加括号为'(' 时: dp[i+1][x][k+1] += dp[i][j][k] 

当新加括号为'(' 并且 k>0 时: dp[i+1][x][k-1] += dp[i][j][k]

同时也要注意:j = len 时,这一行上面的两行转移方程中 x 一直为len;

 

还要注意一点:k 的大小我们更新到初始的n值就够了,否则会超时

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 200 + 7;
const int mod = 1e9 + 7;
int n, len, m;
char t[maxn];
int f[maxn], dp[maxn][maxn][maxn] = {0};

int main() {
  scanf("%d%s", &n, t+1);
  m = n; n <<= 1;
  len = strlen(t+1);
  f[1] = f[2] = 1;
  for(int i = 2; i < len; ++i) {
    int j = f[i];
    while(j > 1 && t[j] != t[i]) j = f[j];
    f[i+1] = (t[j] == t[i] ? j+1 : 1);
  }
  dp[0][0][0] = 1;
  for(int i = 0; i < n; ++i) {
    for(int j = 0; j <= len; ++j) {
      for(int k = 0; k <= m; ++k) {
        if(j == len) {
          (dp[i+1][j][k+1] += dp[i][j][k] ) %= mod;
          if(k) (dp[i+1][j][k-1] += dp[i][j][k] ) %= mod;
          continue;
        }
        char c = '(';
        int j_ = j+1;
        while(j_ > 1 && t[j_] != c) j_ = f[j_];
        if(t[j_] != c) j_--;
        (dp[i+1][j_][k+1] += dp[i][j][k] ) %= mod;
        if(k) {
          char c = ')';
          int j_ = j+1;
          while(j_ > 1 && t[j_] != c) j_ = f[j_];
          if(t[j_] != c) j_--;
          (dp[i+1][j_][k-1] += dp[i][j][k] ) %= mod;
        }
      }
    }
  }
  //for(int i = 0; i <= n; ++i) {
    cout << dp[n][len][0] << endl;
  //}
  return 0;
}


/*
                       .::::.
                     .::::::::.
                    :::::::::::  I want to say...Accepted!
                ..:::::::::::'
              '::::::::::::'
                .::::::::::
           '::::::::::::::..
                ..::::::::::::.
              ``:::::::::::::::·
               ::::``:::::::::'        .:::.
              ::::'   ':::::'       .::::::::.
            .::::'      ::::     .:::::::'::::.
           .:::'       :::::  .:::::::::' ':::::.
          .::'        :::::.:::::::::'      ':::::.
         .::'         ::::::::::::::'         ``::::.
     ...:::           ::::::::::::'              ``::.
    ```` ':.          ':::::::::'                  ::::..
                       '.:::::'                    ':'````..
 
    ******************** 美↑女坐键↓盘 ********************
┌───┐   ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┐
│Esc│   │ F1│ F2│ F3│ F4│ │ F5│ F6│ F7│ F8│ │ F9│F10│F11│F12│ │P/S│S L│P/B│  ┌┐    ┌┐    ┌┐
└───┘   └───┴───┴───┴───┘ └───┴───┴───┴───┘ └───┴───┴───┴───┘ └───┴───┴───┘  └┘    └┘    └┘
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐ ┌───┬───┬───┐ ┌───┬───┬───┬───┐
│~ `│! 1│@ 2│# 3│$ 4│% 5│^ 6│& 7│* 8│( 9│) 0│_ -│+ =│ BacSp │ │Ins│Hom│PUp│ │N L│ / │ * │ - │
├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤ ├───┼───┼───┤ ├───┼───┼───┼───┤
│ Tab │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │{ [│} ]│ | \ │ │Del│End│PDn│ │ 7 │ 8 │ 9 │   │
├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤ └───┴───┴───┘ ├───┼───┼───┤ + │
│ Caps │ A │ S │ D │ F │ G │ H │ J │ K │ L │: ;│" '│ Enter  │               │ 4 │ 5 │ 6 │   │
├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤     ┌───┐     ├───┼───┼───┼───┤
│ Shift  │ Z │ X │ C │ V │ B │ N │ M │< ,│> .│? /│  Shift   │     │ ↑ │     │ 1 │ 2 │ 3 │   │
├─────┬──┴─┬─┴──┬┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤ ┌───┼───┼───┐ ├───┴───┼───┤ E││
│ Ctrl│    │Alt │         Space         │ Alt│    │    │Ctrl│ │ ← │ ↓ │ → │ │   0   │ . │←─┘│
└─────┴────┴────┴───────────────────────┴────┴────┴────┴────┘ └───┴───┴───┘ └───────┴───┴───┘
*/




 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值