這道題n-m很小,可以從此入手
記f[i][j]為i個字符括號綜合為j的合法方案數
則第i個括號可以枚舉為(和),所以f[i][j]=f[i-1][j-1]+f[i-1][j+1],小心越界
再記a為序列總和,b為序列中前綴和最小值
則我們可以枚舉i,j統計答案,設前面括號的長度和權值為i,j
那麼中間的長度和權值為m,a,所以後面為n-m-i,-j-a
但是這樣子做會越界,我們可以考慮將所有後面的方案翻轉(左括變右,右括變左),方案合法,權值變負
這樣子,後面方案為n-m-i,j+a,所以不會越界,將所有方案乘起來即可
#include<bits/stdc++.h>
using namespace std;
int f[2010][2010],n,m,a,r,b;
#define mo 1000000007
char s[100010];
int main(){
freopen("bracket.in","r",stdin);
freopen("bracket.out","w",stdout);
scanf("%d%d",&n,&m);
scanf("%s",s+1);
for(int i=1;i<=m;i++){
if(s[i]==')')a--;
else a++;
b=min(b,a);
}
f[0][0]=1;
for(int i=1;i<=n-m;i++)
for(int j=0;j<=i;j++){
if(j>0)f[i][j]=(f[i][j]+f[i-1][j-1])%mo;
if(j<i-1)f[i][j]=(f[i][j]+f[i-1][j+1])%mo;
}
for(int i=0;i<=n-m;i++)
for(int j=-b;j<=i;j++)
if(a+j<=n-m-i)r=(r+(long long)f[i][j]*f[n-i-m][j+a])%mo;
printf("%d",r);
}