"蔚来杯"2022牛客暑期多校训练营2 K Link with Bracket Sequence I
K Link with Bracket Sequence I
题目大意:给定一个长度为\(n\)的括号序列\(a\),\(a\)是一个长度为\(m\)的合法括号序列\(b\)的子序列,求\(b\)的方案数
(\(mod\ 10^9+7,1<=n<=m<=200\) )
解题思路:考虑类似最长公共子序列的动态规划,加上括号序列需要合法的限制
定义状态:
\[dp[i][j][k]:=b的前i个最多匹配a的前j个,剩下k个左括号未匹配的方案数
\]
状态转移:
\(b\)多放一个左括号
\[a_{j+1}==')'\ \ \Longrightarrow \ \ dp[i][j][k]\longrightarrow dp[i+1][j][k+1]\\
a_{j+1}=='('\ \ \Longrightarrow \ \ dp[i][j][k]\longrightarrow dp[i+1][j+1][k+1]
\]
\(b\)多放一个右括号
\[a_{j+1}=='('\ \ \Longrightarrow \ \ dp[i][j][k]\longrightarrow dp[i+1][j][k-1]\\
a_{j+1}==')'\ \ \Longrightarrow \ \ dp[i][j][k]\longrightarrow dp[i+1][j+1][k-1]
\]
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (int)(a); i <= (int)(b); i ++)
const int N = 210, MOD = 1e9 + 7;
int dp[N][N][N];
char a[N];
void work() {
int n,m;
cin>>n>>m>>a+1;
memset(dp,0,sizeof dp);
dp[0][0][0]=1;
rep(i,0,m-1){
rep(j,0,min(i,n)){
rep(k,0,i){
// '('
if(a[j+1]=='(') dp[i+1][j+1][k+1]=(dp[i+1][j+1][k+1]+dp[i][j][k])%MOD;
else dp[i+1][j][k+1]=(dp[i+1][j][k+1]+dp[i][j][k])%MOD;
// ')'
if(!k) continue;
if(a[j+1]==')') dp[i+1][j+1][k-1]=(dp[i+1][j+1][k-1]+dp[i][j][k])%MOD;
else dp[i+1][j][k-1]=(dp[i+1][j][k-1]+dp[i][j][k])%MOD;
}
}
}
cout<<dp[m][n][0]<<endl;
}
signed main() {
int test=1;
cin >> test;
while (test--)
work();
return 0;
}

浙公网安备 33010602011771号