Codeforces 1015F Bracket Substring

题目蓝链

Description

给定一个正整数\(n\),问有多少个长度为\(2n\)的合法括号序列包含一个给定的子括号序列\(s\)(不一定合法)

\(n \leq 100, |s| \leq 200\)

Solution

我们可以先预处理出\(to[i][0/1]\),表示如果后缀已经\(s\)匹配上了前\(i\)个字符,再填一个左/右括号后,后缀和\(s\)前缀匹配的长度。这个东西可以直接暴力预处理,也可以用\(kmp\)来处理

然后就是设\(dp[i][j][k][0/1]\),表示考虑到第\(i\)个位置,左括号比右括号多\(i\)个,当前后缀和\(s\)已经匹配上了\(k\)位,当前串是否已经包含了\(s\)串。转移就直接枚举当前位置填什么,并利用预处理出来的\(to\)数组转移

Code

#include <bits/stdc++.h>

using namespace std;

#define fst first
#define snd second
#define mp make_pair
#define squ(x) ((LL)(x) * (x))
#define debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef pair<int, int> pii;

template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }

inline int read() {
    int sum = 0, fg = 1; char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') fg = -1;
    for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30);
    return fg * sum;
}

const int maxn = 200 + 10;
const int mod = 1e9 + 7;

inline void Add(int &x, int y) { x += y, x -= (x >= mod ? mod : 0); }

int n, m, dp[maxn][maxn][maxn][2], to[maxn][2];
char s[maxn];

int fail[maxn];
inline void get_next() {
    for (int i = 2, j = 0; i <= m; i++) {
        while (j && s[j + 1] != s[i]) j = fail[j];
        if (s[j + 1] == s[i]) ++j;
        fail[i] = j;
    }
}

int main() {
#ifdef xunzhen
    freopen("bracket.in", "r", stdin);
    freopen("bracket.out", "w", stdout);
#endif

    n = read() << 1, scanf("%s", s + 1), m = strlen(s + 1);

    get_next();
    for (int i = 0; i < m; i++) {
        int j = i;
        while (j && s[j + 1] != '(') j = fail[j];
        if (s[j + 1] == '(') to[i][0] = j + 1;
        j = i;
        while (j && s[j + 1] != ')') j = fail[j];
        if (s[j + 1] == ')') to[i][1] = j + 1;
    }

    dp[0][0][0][0] = 1;
    for (int i = 0; i < n; i++)
        for (int j = 0; j <= i; j++) {
            for (int k = 0; k < m; k++) {
                if (j) Add(dp[i + 1][j - 1][to[k][1]][to[k][1] == m], dp[i][j][k][0]);
                Add(dp[i + 1][j + 1][to[k][0]][to[k][0] == m], dp[i][j][k][0]);
            }
            if (j) Add(dp[i + 1][j - 1][m][1], dp[i][j][m][1]);
            Add(dp[i + 1][j + 1][m][1], dp[i][j][m][1]);
        }

    cout << dp[n][0][m][1] << endl;

    return 0;
}
posted @ 2019-08-30 21:22 xunzhen 阅读(...) 评论(...) 编辑 收藏