比赛期间有想到是dp,但是并没有写出状态转移方程..只好去看了一下网上的题解
dp[i][j]表示前缀为i个字符且左括号数-右括号数j的最优解。
则当j==0时,dp[i][j]+=dp[i-1][j+1];
当j>=0时,dp[i][j]+=dp[i-1][j+1]+dp[i-1][j-1];
先计算出字符串s的平衡度S,然后枚举p串的平衡度。
p串从左向右看,q串从右向左看。
当p串的平衡度为P,则q串的平衡度即为p+s(从右向左看)。
则ans+=dp[i][j]*dp[n-m-i][j+s]%mod;
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; typedef __int64 LL; const LL mod=1000000007; const int INF=0x3f3f3f3f; const int maxn=100010; int n,m; char s[maxn]; LL dp[2005][2005]; int main(){ #ifndef ONLINE_JUDGE freopen("test.in","r",stdin); freopen("test.out","w",stdout); #endif while(~scanf("%d%d",&n,&m)){ scanf("%s",s+1); dp[0][0]=1; for(int i=1;i<=n-m;i++){ for(int j=0;j<=i;j++){ if(j==0) dp[i][j]+=dp[i-1][j+1]; else dp[i][j]+=dp[i-1][j-1]+dp[i-1][j+1]; dp[i][j]%=mod; } } int cnt=0,d=INF; for(int i=1;i<=m;i++){ if(s[i]=='(') cnt++; else cnt--; d=min(d,cnt); } LL ans=0; for(int i=0;i<=n-m;i++){ for(int j=0;j<=i;j++){ if(j+d>=0&&j+cnt<=n-m-i){ ans+=(dp[i][j]*dp[n-m-i][j+cnt])%mod; ans%=mod; } } } printf("%I64d\n",ans); } return 0; }