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;
}