所有符合规范的超级括号序列均可通过上述 3 条规则得到。
现在给出一个长度为 n n n的超级括号序列,一些位置的字符尚未确定(用 ? 表示)。求有多少种方法,使得得到的字符串是一个符合规范的超级括号序列?
1 ≤ k ≤ n ≤ 500 。 1 \le k \le n \le 500。 1≤k≤n≤500。
设 f l , r f_{l,r} fl,r为 l ∼ r l \sim r l∼r符合规范的序列方案, S l , r S_{l,r} Sl,r为 l ∼ r l \sim r l∼r是否可以拼成一个 S S S。
第一种情况以及第三种情况中的(A),直接判断两端是否可以为括号,中间是否可以为 S S S。
第三种情况,枚举断点即可。
对于第二种情况,需要枚举 S S S,发现 S S S的左端点是随着右端点向右移而右移的,可以用前缀和优化。
注意到ASASA,这种情况会被计算2遍,所以第二种分开计算即可。
时间复杂度 O ( N 3 ) O(N^3) O(N3)
#include
#define int long long
const int mod = 1e9 + 7;
int n, lim;
char s[511];
int f[511][511], S[511][511], g[511][511];
signed main() {
scanf("%lld %lld", &n, &lim);
scanf("%s", s + 1);
for (int i = 1; i <= n; i++) {
S[i][i - 1] = 1;
for (int j = i; j - i + 1 <= lim && j <= n; j++)
S[i][j] = S[i][j - 1] & (s[j] == '*' || s[j] == '?');
}
for (int i = n; i >= 1; i--)
for (int j = i; j <= n; j++) {
if ((s[i] == '(' || s[i] == '?') && (s[j] == ')' || s[j] == '?')) {
(f[i][j] += f[i + 1][j - 1] + S[i + 1][j - 1]) %= mod;//第一种
for (int k = i + 1; k < j - 1; k++)
(f[i][j] += f[i + 1][k] * S[k + 1][j - 1] + f[k + 1][j - 1] * S[i + 1][k]) %= mod;//第三种
}
g[i][j] = f[i][j];//去重
int sum = 0, l = i;
for (int r = i + 1; r < j; r++) {//第二种
(sum += f[i][r]) %= mod;
while (!S[l][r]) {
(sum -= f[i][l]) %= mod;
l++;
}
(f[i][j] += (sum + f[i][l - 1]) * g[r + 1][j]) %= mod;
}
}
printf("%lld", (f[1][n] + mod) % mod);
}