您的位置:首页 > 其它

Codeforces Round #343 (Div. 2)C. Famil Door and Brackets DP

2016-02-27 11:13 387 查看
转自:Codeforces Round #343 (Div. 2) 解题报告

题意:给你一个由括号组成的字符串,长度为m,现在希望获得一个长度为n(全由括号组成)的字符串,0<=n-m<=2000

这个长度为n的字符串要求有两个性质:

就是任意前缀,左括号数量大于右括号数量
字符串中左括号的数量等于右括号


现在让你可以在长度为m的原串前加一个括号串p,在原串后加一个括号串q 最后p+m+q=n

问有多少种组合p,q能得到目标串

题目思路:

定义dp[i][j],为前缀长为i,且左括号数量-右括号数量=j的串有多少个

算出s段左括号与右括号的差值记为cnt,记录p段至少需要的左括号数目为need。

然后枚举p的长度和平衡值 对于长度i, 当-d<=j时,p可以加到前面

然后当p确定后,q的长度也确定,因为最终 左=右 ,所以q 的(右-左)的代价也知道了

假设当前是i,平衡度是j,所以只要将dp[i][j]*dp[n-m-i][j+cnt]加到答案就行了

注意:dp[i][j]代表前缀i,平衡度为j的方案数, dp[n-m-i][j+cnt]为后缀n-m-i,平衡度为-(j+cnt)的方案数,是对称的,很重要

即:dp[n - m - i][j + cnt] = dp[n - m - i][-(j + cnt)] // dp第二维不可为负数

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn = 2010;
const int mod = 1e9 + 7;
const int INF = 10000000000;
int N, M;
char s[100010];
LL dp[maxn][maxn];
void add(LL &a, LL b) {
a += b;
if (a >= mod) {
a -= mod;
}
}
int main() {
scanf("%d%d",&N,&M);
scanf("%s",s+1);
memset(dp,0,sizeof(dp));
dp[0][0] = 1;
for (int i = 1; i <= N - M; i++) {
for (int j = 0; j <= i; j++) {
add(dp[i][j],dp[i-1][j+1]);
if (j > 0) {
add(dp[i][j],dp[i-1][j-1]);
}
}
}
int minv = INF;
int num = 0;
for (int i = 1; i <= M; i++) {
if (s[i] == '(')num++;
else num--;
minv = min(minv,num);
}
LL ans = 0;
for (int i = 0; i <= N - M; i++) {
for (int j = 0; j <= i; j++) {
if (j + minv >= 0 && j + num <= N - M - i) {
add(ans,dp[i][j]*dp[N-M-i][j+num]%mod);
}
}
}
cout<<ans<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: