分析
我們將左括號看作 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;
}