题目链接
题目大意
给定我们一个长度为 n n n的括号序列,并且告诉我们它是一个长度为 m m m的合法的括号序列的子串,问我们这个长度为 m m m的括号序列有多少种情况?
题解
考虑DP,设 f i , j , k f_{i,j,k} fi,j,k 表示考虑 b b b串的前i个字符,和 a a a串的最长公共子序列长度为 j j j,左括号比右括号多 k k k,每次转移的时候枚举当前是左括号还是右括号,最后答案即为 f [ m ] [ n ] [ 0 ] f_{[m][n][0]} f[m][n][0]。
代码
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 210;
const int mod = 1e9 + 7;
int f[maxn][maxn][maxn];
int main()
{
int t; cin >> t;
while(t --)
{
memset(f, 0, sizeof f);
int n, m; cin >> n >> m;
string s; cin >> s;
s = ' ' + s;
f[0][0][0] = 1;
for(int i = 1; i <= m; i ++){
for(int j = 0; j <= n && j <= i; j ++){
for(int k = 0; k <= i; k ++){
if(k) {
if(j && s[j] == '(') f[i][j][k] = (f[i][j][k] + f[i - 1][j - 1][k - 1]) % mod;
else f[i][j][k] = (f[i][j][k] + f[i - 1][j][k - 1]) % mod;
}
if(k != m) {
if(!j || s[j] == '(') f[i][j][k] = (f[i][j][k] + f[i - 1][j][k + 1]) % mod;
else f[i][j][k] = (f[i][j][k] + f[i - 1][j - 1][k + 1]) % mod;
}
}
}
}
cout << f[m][n][0] << endl;
}
}