CodeForces 629C Famil Door and Brackets

DP。

具体做法:dp[i][j]表示长度为 i 的括号串,前缀和(左括号表示1,右括号表示-1)为 j 的有几种。

状态转移很容易得到:dp[i][j]=dp[i - 1][j + 1]+dp[i - 1][j - 1],表示 i 这位分别放上右括号和左括号。

然后就是要处理题目的问题了:

我们可以枚举P串的长度和P串的前缀和,来看这种情况下是否符合题目要求,如果符合答案增加。

那么如何判断P串长度为left,前缀和为p的情况下,有几种符合题目要求呢?

先对已经存在的那个S串做一次括号匹配,做完之后剩下的肯定是 L个右括号+R个左括号

接下来的过程都是从左往右看P串,从右往左看Q串

我们假设P串的前缀和是p,S串的前缀和是k,很容易得到k=R-L;我们根据p和k可以推出Q串的前缀和是p+k(注意:Q串是从右往左看的

我们需要保证p+k>=0&&p+k<=n-m,此外还需要保证 P串的前缀和 - L >=0,即p - L >= 0,Q串前缀和 - R>=0,即p + k - R >= 0

满足上述几个条件,答案增加 dp[left][p] * dp[right][p + k] 

题外话:卡特兰数第n项,就是dp[2*n][0]。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<vector>
#include<queue>
#include<algorithm>
#include<iostream>
using namespace std;

const int maxn = 100000 + 10;
char s[maxn];
char st[maxn];
int top;
long long dp[2000 + 10][2000 + 10];
long long MOD = 1e9 + 7;
int n, m;
long long ans;
long long k;

void read()
{
    scanf("%d%d", &n, &m);
    scanf("%s", s);
}

void init()
{
    memset(dp, 0, sizeof dp);
    memset(st, 0, sizeof st);
    ans = 0; k = 0; top = -1;
}

void work()
{
    for (int i = 0; s[i]; i++)
    {
        if (top == -1) st[++top] = s[i];
        else
        {
            if (st[top] == '('&&s[i] == ')') st[top] = 0, top--;
            else st[++top] = s[i];
        }
    }

    int L = 0, R = 0;
    for (int i = 0; st[i]; i++)
    {
        if (st[i] == ')') L++;
        else break;
    }
    R = strlen(st) - L;
    k = R - L;

    dp[0][0] = 1;

    for (int i = 1; i <= n - m; i++)
    {
        for (int j = 0; j <= n - m; j++)
        {
            if (j + 1 <= n - m) dp[i][j] = (dp[i][j] + dp[i - 1][j + 1]) % MOD;
            if (j - 1 >= 0) dp[i][j] = (dp[i][j] + dp[i - 1][j - 1]) % MOD;
        }
    }

    for (int left = 0; left <= n - m; left++)
    {
        int right = n - m - left;

        for (int p = 0; p <= left; p++)
        {
            if (p + k >= 0 && p - L >= 0 && p + k - R >= 0 && p + k <= n - m)
                ans = (ans + (dp[left][p] * dp[right][p + k]) % MOD) % MOD;
        }
    }

    printf("%lld\n", ans);

}

int main()
{
    read();
    init();
    work();
    return 0;
}

 

posted @ 2016-02-23 09:53  Fighting_Heart  阅读(339)  评论(0编辑  收藏  举报