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 }