
629C
题目大意:给你一个由括号组成的字符串,长度为m,现在希望获得一个长度为n(全由括号组成)的字符串,0<=n-m<=2000这个长度为n的字符串要求有两个性质:就是任意前缀,左括号数量大于右括号数量字符串中左括号的数量等于右括号现在让你可以在长度为m的原串前加一个括号串p,在原串后加一个括号串q 最后p+m+q=n问有多少种组合p,q能得到目标串
题解:定义dp[i][j],为前缀长为i,且左括号数量-右括号数量=j的串有多少个,反过来也一样,最后dp*dp累加即可
不过要判断给定串中左括号很大的情况
[cpp] view plain copy
- #include <set>
- #include <map>
- #include <stack>
- #include <queue>
- #include <deque>
- #include <cmath>
- #include <vector>
- #include <string>
- #include <cstdio>
- #include <cstdlib>
- #include <cstring>
- #include <iostream>
- #include <algorithm>
- using namespace std;
- #define L(i) i<<1
- #define R(i) i<<1|1
- #define INF 0x3f3f3f3f
- #define pi acos(-1.0)
- #define eps 1e-9
- #define maxn 100100
- #define MOD 1000000007
-
- int n,m;
- char s[maxn];
- long long dp[2020][2020];
-
- int main()
- {
- //freopen(","r",stdin);
- //freopen(","w",stdout);
- int t,C = 1;
- //scanf("%d",&t);
- while(scanf("%d%d",&n,&m) != EOF)
- {
- scanf("%s",s);
- if(n & 1)
- {
- printf("0n");
- continue;
- }
- int Max = -INF;
- int l = 0,r = 0;
- for(int i = 0; i < strlen(s); i++)
- {
- if(s[i] == '(')
- l++;
- else
- r++;
- Max = max(Max,r - l);
- }
- memset(dp,0,sizeof(dp));
- dp[0][0] = 1;
- for(int i = 1; i <= n-m; i++)
- for(int j = 0; j <= i; j++)
- {
- dp[i][j] = dp[i-1][j+1];
- if(j > 0)
- dp[i][j] += dp[i-1][j-1];
- dp[i][j] %= MOD;
- //printf("%d %d %dn",i,j,dp[i][j]);
- }
- long long ans = 0;
- for(int i = 0; i <= n-m; i++)
- for(int j = max(Max,0); j <= i; j++)
- {
- if(l - r + j > n-m-i)
- break;
- ans += dp[i][j] * dp[n-m-i][j+l-r]; //正反等价交替
- ans %= MOD;
- }
- printf("%lldn",ans);
- }
- return 0;
- }