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

来源:互联网 发布:淘宝网充值平台2016 编辑:程序博客网 时间:2024/06/06 03:43

转自: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;}
0 0
原创粉丝点击