分析
我们将左括号看作 1,右括号看作 -1,则一个合法的括号序列需要满足:
*所有括号的总和为 0
*每个前缀和均不小于0
我们先统计出串 s 的总和 a 以及最小的前缀和 b,然后枚举串 p 的长度 i 以及总和 j, 考虑到需要满足第二个条件,那么 j 需要满足 j+b>=0。记 f[ i ][ j ] 为长度为 i ,总和为 j 的括号序列数量,此时 p 的方案数为 f[ i ][ j ],q 的方案数为 f[ n - m - i ][ j + a ],将它们的乘积计入答案即可。
f 可以通过一个简单的 DP 求出,时空复杂度均为 O((n-m)^2)。
#include<bits/stdc++.h>
#define ll long long
#define N 100005
#define M 2005
#define mod 1000000007
using namespace std;
int n,m,k,u,ans,f[M][M];
char s[N];
int main(){
scanf("%d%d",&n,&m);
scanf("%s",s+1);
for(int i=1;i<=m;i++){
u+=s[i]=='(' ? 1:-1;
k=min(k,u);
}
f[0][0]=1;
for(int i=1;i<=n-m;i++)
for(int j=0;j<=i;j++){
f[i][j]=0;
if(j>0)f[i][j]=(f[i][j]+f[i-1][j-1])%mod;
if(j<i-1)f[i][j]=(f[i][j]+f[i-1][j+1])%mod;
}
for(int i=-k;i<=n-m;i++)
for(int j=-k;j<=i;j++)
if(u+j<=n-m-i) ans=(ans+(ll)f[i][j]*f[n-m-i][u+j])%mod;
printf("%d",ans);
return 0;
}