题解
- 我们可以把左括号看成+1,右括号看成-1
- 那么一个合法的括号序列就是左括号>=右括号
- 设f[i][j]为长度为i的序列 左括号比右括号多j个 的方案数
- 状态转移方程明显就是:f[i-1][j-1]+f[i-1][j+1]
- 那么考虑如何求最终的方案数
- 首先要满足左括号多于右括号,和 |p| + |s| + |q| = n
- 每次枚举一个i表示前面的p序列的长度,再枚举一个j表示p序列左括号比右括号多的个数
- 那么就是f[i][j]*f[n-m-i][j+tot](tot为原来序列中左括号比右括号多的个数)
代码
1 #include <cstdio>
2 #include <iostream>
3 #include <algorithm>
4 #include <cstring>
5 using namespace std;
6 const long long mo=1e9+7;
7 int n,m,tot,ltot;
8 char s[100010];
9 long long ans,f[2010][2010];
10 int main()
11 {
12 freopen("bracket.in","r",stdin);
13 freopen("bracket.out","w",stdout);
14 scanf("%d%d",&n,&m);
15 scanf("%s",s);
16 for (int i=0;i<m;i++)
17 {
18 if (s[i]=='(') tot++; else tot--;
19 if (i==0) ltot=tot; else ltot=min(tot,ltot);
20 }
21 f[0][0]=1;
22 for (int i=1;i<=n-m;i++)
23 for (int j=0;j<=i;j++)
24 if (j==0) f[i][j]=f[i-1][j+1];
25 else f[i][j]=(f[i-1][j-1]+f[i-1][j+1])%mo;
26 for (int i=0;i<=n-m;i++)
27 for (int j=0;j<=i;j++)
28 if (j+tot<=n-m&&j+ltot>=0)
29 (ans+=f[i][j]*f[n-m-i][j+tot])%=mo;
30 printf("%lld",ans);
31 return 0;
32 }