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 }

 

posted @ 2016-11-23 12:30  as3asddd  阅读(219)  评论(0编辑  收藏  举报