codeforces629C Famil Door and Brackets (dp)

题意:给你一个长度为n的括号匹配串(不一定恰好匹配),让你在这个串的前面加p串和后面加上q串,使得这个括号串平衡(平衡的含义是对于任意位置的括号前缀和大于等于0,且最后的前缀和为0)。

思路:枚举这个字符串前面p字符串的长度,我们可以使得p字符串的前缀和大于等于字符串s的最小前缀和minx,那么p+s就符合前缀和大于等于0,然后q的方案数也能确定了。我们用dp[i][j]表示i个括号平衡度为j的方案数,那么可以先预处理出来dp的值。然后我们算出s字符串的最小前缀和minx,最后我们只要枚举p的长度i和平衡度j,那么sum+=dp[i][j]*dp[n-m-i][per_s+j],(per_s是整个s字符串的平衡度,per_s+j为q的平衡度).

 1 #include<iostream>
 2 #include<string>
 3 #include<algorithm>
 4 #include<cstdlib>
 5 #include<cstdio>
 6 #include<set>
 7 #include<map>
 8 #include<vector>
 9 #include<cstring>
10 #include<stack>
11 #include<cmath>
12 #include<queue>
13 #define clc(a,b) memset(a,b,sizeof(a))
14 #include <bits/stdc++.h>
15 using namespace std;
16 #define LL long long
17 const int maxn= 100050;
18 const int inf=0x3f3f3f3f;
19 char s[maxn];
20 const int mod=1000000007;
21 LL dp[2050][2050];
22 
23 int main()
24 {
25     int n,m;
26     scanf("%d%d",&n,&m);
27     scanf("%s",s+1);
28     clc(dp,0);
29     dp[0][0]=1;
30     for(int i=1; i<=n-m; i++)
31     {
32         for(int j=0; j<=i; j++)
33         {
34             if(j>0)
35                 dp[i][j]=(dp[i][j]+dp[i-1][j-1])%mod;
36             dp[i][j]=(dp[i][j]+dp[i-1][j+1])%mod;
37         }
38     }
39     int minx=inf;
40     int per_s=0;
41     for(int i=1; i<=m; i++)
42     {
43         if(s[i]=='(')
44             per_s++;
45         else
46             per_s--;
47         minx=min(minx,per_s);
48     }
49     LL sum=0;
50     for(int i=0; i<=n-m; i++)
51         for(int j=0; j<=i; j++)
52         {
53             if(j+minx>=0&&j+per_s<=n-m-i)
54                 sum=(sum+dp[i][j]*dp[n-m-i][j+per_s])%mod;
55         }
56     cout<<sum<<endl;
57     return 0;
58 }
View Code

 

posted @ 2016-02-23 01:10  yyblues  阅读(351)  评论(0编辑  收藏  举报