【題目鏈接】
http://codeforces.com/problemset/problem/629/C
【解題報告】
比賽的時候跑去做D了,這道題只是簡單看了看,賽後補題把它補掉。這個題目只要想通了還是很水的。
題意很簡單,給你一個長度爲m的串S,讓你求不同的串P和Q的方案數使長度爲n的串P+S+Q爲一個合法括號序列。
合法的括號序列要滿足:
1.左括號和右括號數量相同
2.該串的任意一個前綴滿足左括號數>=右括號數。
那麼我們設dp[i][j]表示長度爲i的串,(比)多j個的方案數
遞推式可以列寫爲:dp[i]j[]=dp[i-1][j-1]+dp[i-1][j+1]
之後我們預處理出s中(比)多的個數,枚舉左邊(比)多的個數即可。
【解題報告】
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF=2e9;
const int maxn=2e5;
const int mod=1e9+7;
LL dp[2010][2010]={0};
void init( int k )
{
dp[0][0]=1;
for( int i=1;i<=k;i++ )
{
dp[i][0]=dp[i-1][1];
for( int j=1;j<=i;j++ )
{
dp[i][j]=(dp[i-1][j-1]+dp[i-1][j+1])%mod;
}
}
}
int main()
{
int n,m; cin>>n>>m;
char s[maxn]; cin>>s;
init( n-m );
int pre=-INF,suf,sum=0;
for( int i=0;i<m;i++ ){
if( s[i]==')' )sum++;
else sum--;
pre=max( pre,sum );
}
sum=0;
for( int i=m-1;i>=0;i-- ) {
if( s[i]=='(' )sum++;
else sum--;
}
suf=sum;
LL ans=0;
for( int i=0;i<=n-m;i++ )
for( int j=0;j<=n-m;j++)
{
int k=j+sum;
if( j>=pre && k>=suf && k<=n-m )
{
ans+=dp[i][j]*dp[n-m-i][k]%mod;
ans%=mod;
}
}
cout<<ans<<endl;
return 0;
}