• 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
    ", ans);
    
    }
    
    int main()
    {
        read();
        init();
        work();
        return 0;
    }
  • 相关阅读:
    个人阅读作业
    软件工程基础/个人项目1
    个人阅读作业3
    个人阅读作业2
    代码复审
    软件工程:结对编程1
    个人阅读作业
    软工作业1:单词统计
    有关敏捷开发的一点感想[110617班 刘耀先]
    Pair Project: Elevator Scheduler [电梯调度算法的实现和测试][关于电梯调度算法的附加思考]:刘耀先-11061183,罗凡-11061174
  • 原文地址:https://www.cnblogs.com/zufezzt/p/5208925.html
Copyright © 2020-2023  润新知