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  阅读(269)  评论(1编辑  收藏  举报