Codeforces 629C Famil Door and Brackets DP
题目:http://codeforces.com/contest/629/problem/C
题目大意:有一个括号串s长度为m,你可以在这个串的头部和尾部增加括号使得串长度变成n并且满足,对所有的前缀 '('的数不比')'少,并且最后构造成的串必须'('的数量和')'的数量相等
思路:DP 把‘(’看作1把')'看作-1,那么也就是这个串要满足对任意位置prex(i)>=0, dp[i][j]表示串长度为i,和为j时的方案数
dp[i][j]=dp[i-1][i-1]+dp[i-1][j+1](实际上dp[i][j]和dp[i][-j]是等价的,因为只要把1和-1反过来 方案数还是不会变的)
n-m<=2000,那么预处理所有的情况
这样枚举p串的长度是i,前缀和是j时的情况
j+mi>=0&&pre+j<=n-m-i
sum+=(dp[i][j]*dp[n-m-i][pre+j])
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 const int maxn=3010; 7 const int mod=1e9+7; 8 long long dp[maxn][maxn]; 9 void get_(){ 10 dp[0][0]=1; 11 for(int i=1;i<=2010;i++){ 12 for(int j=0;j<=i;j++){ 13 if(j)dp[i][j]=(dp[i][j]+dp[i-1][j-1])%mod; 14 dp[i][j]=(dp[i][j]+dp[i-1][j+1])%mod; 15 } 16 } 17 } 18 int main(){ 19 get_(); 20 int n,m; 21 while(scanf("%d %d",&n,&m)!=EOF){ 22 int pre=0; 23 int mi=0; 24 for(int i=1;i<=m;i++){ 25 char tmp; 26 scanf(" %c",&tmp); 27 if(tmp=='(') pre++; 28 else pre--; 29 mi=min(pre,mi); 30 } 31 long long sum=0; 32 for(int i=0;i<=n-m;i++){ 33 for(int j=0;j<=i;j++){ 34 if(mi+j>=0&&j+pre<=n-m-i){ 35 (sum+=((dp[i][j]%mod*dp[n-m-i][pre+j]%mod)%mod))%=mod; 36 } 37 } 38 } 39 printf("%lld\n",sum%mod); 40 } 41 return 0; 42 }