CodeForces 1015F - Bracket Substring (KMP + dp)

题目链接

题意:

给你一个括号序列 s s s 和一个数 n n n ,让你求出长度为 2 ∗ n 2 * n 2n 并且 s s s 是最后串里面的一个子串的合法括号序列有多少种。 m o d ( 1 e 9 + 7 ) mod (1e9 + 7) mod(1e9+7)

参考 b l o g blog blog

分析:

先确定 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k] 表示最后的串到第 i i i 位,后缀匹配到长度为 j j j 的原串,有 k k k 个未匹配的左括号的方案数有多少个。

为什么要这样定义状态呢,如果只是单纯地定义 d p [ i ] [ k ] dp[i][k] dp[i][k] 的话,你不能够确定这些串里面是否含有 s s s(感觉是废话)。

那么转移就是 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k] + = += += ∑ x 所 有 可 能 的 后 缀 情 况 d p [ i − 1 ] [ k ] [ x ] [ 看 当 前 为 是 ′ ( ′ 还 是 ′ ) ′ , 来 决 定 ] \sum_{x}^{所有可能的后缀情况} dp[i - 1][k][x][看当前为是 '(' 还是 ')',来决定] xdp[i1][k][x][()]

但是这样的转移好像很麻烦,我们换成

d p [ i ] [ 当 前 位 填 ′ ( ′ 后 对 应 的 原 串 后 缀 长 度 ] [ k + 1 ] dp[i][当前位填'('后对应的原串后缀长度][k + 1] dp[i][(][k+1] + = += += d p [ i − 1 ] [ j ] [ k ] dp[i - 1][j][k] dp[i1][j][k]
d p [ i ] [ 当 前 位 填 ′ ) ′ 后 对 应 的 原 串 后 缀 长 度 ] [ k ] dp[i][当前位填')'后对应的原串后缀长度][k] dp[i][)][k] + = += += d p [ i − 1 ] [ j ] [ k + 1 ] dp[i - 1][j][k + 1] dp[i1][j][k+1]

是不是感觉很简单,然后这个 当前位填 ‘(’ or ‘)’ 后对应的原串后缀长度 可以用 K M P KMP KMP n e x t next next 数组来优化,我直接预处理出来一个数组 t o [ x ] [ i ] to[x][i] to[x][i] 表示当前串后缀已经和原串匹配了长度 x x x ,接下来填 ‘ ( ’ ‘(’ ( ( i = 0 ) (i = 0) (i=0) ‘ ) ’ ‘)’ ) ( i = 1 ) (i = 1) (i=1) 后,后缀和原串对应的匹配长度。然后就可以愉快的 d p dp dp 了。

当匹配到长度和原串相同时,就直接转移到 l e n len len 统计答案。

最后答案就是 d p [ 2 ∗ n ] [ l e n ] [ 0 ] dp[2 * n][len][0] dp[2n][len][0]

代码:

#include <bits/stdc++.h>
#include <ext/rope>
using namespace __gnu_cxx;
using namespace std;
#define mst(a,b) memset(a,b,sizeof(a))
#define ALL(x) x.begin(),x.end()
#define pii pair<int, int>
#define debug(a) cout << #a": " << a << endl;
#define eularMod(a, b) a < b ? a : a % b + b
inline int lowbit(int x){ return x & -x; }
typedef long long LL;
typedef unsigned long long ULL;
const int N = 1e5 + 10;
const long long mod = 1000000007;
const int INF = 0x3f3f3f3f;
const long long LINF = 0x3f3f3f3f3f3f3f3fLL;
const double PI = acos(-1.0);
const double eps = 1e-6;

char s[205];
int n;
int nex[205];
int to[205][2];
int dp[205][205][205];

int main() {
#ifdef purple_bro
    freopen("in.txt", "r", stdin);
//    freopen("out.txt","w",stdout);
#endif
    scanf("%d%s", &n, s);

    n <<= 1;

    int len = strlen(s);

    nex[0] = 0;
    nex[1] = 0;

    for (int i = 1; i < len; i++) {
        int tmp = nex[i];

        for (;tmp && s[tmp] != '(';)
            tmp = nex[tmp];

        to[i][0] = (s[tmp] == '(') ? tmp + 1 : 0;

        tmp = nex[i];

        for (;tmp && s[tmp] != ')';)
            tmp = nex[tmp];

        to[i][1] = (s[tmp] == ')') ? tmp + 1 : 0;

        int j = nex[i];

        for (;j && s[j] != s[i];)
            j = nex[j];

        nex[i + 1] = (s[i] == s[j]) ? j + 1 : 0;
    }

    for (int i = 1; i <= n; i++) {
        if (i == 1) {
            if (s[0] == '(')
                dp[i][1][1] = 1;
            else
                dp[i][0][1] = 1;
            continue;
        }

        for (int j = 0; j <= len && j < i; j++) {
            for (int k = 0; k < i; k++) {
                if (j < len) {
                    if (s[j] == '(')
                        (dp[i][j + 1][k + 1] += dp[i - 1][j][k]) %= mod;
                    else 
                        (dp[i][to[j][0]][k + 1] += dp[i - 1][j][k]) %= mod;
                        
                    if (s[j] == ')')
                        (dp[i][j + 1][k] += dp[i - 1][j][k + 1]) %= mod;
                    else 
                        (dp[i][to[j][1]][k] += dp[i - 1][j][k + 1]) %= mod;
                } else {
                    (dp[i][j][k + 1] += dp[i - 1][j][k]) %= mod;
                    (dp[i][j][k] += dp[i - 1][j][k + 1]) %= mod;
                    //只转移到 len
                }
            }
        }
    }

    printf("%d\n", dp[n][len][0]);

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值