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;
}
时间: 2024-11-05 14:42:53

CodeForces 629C Famil Door and Brackets的相关文章

codeforces 629C Famil Door and Brackets (dp + 枚举)

题目链接: codeforces 629C Famil Door and Brackets 题目描述: 给出完整的括号序列长度n,现在给出一个序列s长度为m.枚举串p,q,使得p+s+q是合法的括号串,长度为n,问p,q的取值数目. 解题思路: 枚举p的长度,可以直接得到q的长度.因为要满足在任意位置'(' 数目大于 ’)‘ 的数目,所以统计一下s串中 ’(‘ - ')' 的最小数目minx.dp[i][j] 代表 到位置 i 时,满足 '(' - ')' == j 的情况数目.然后枚举p的 j

codeforces 508 E. Arthur and Brackets

题目链接: http://codeforces.ru/problemset/problem/508/E 题意: 有n对括号,按顺序,给出每对括号长度的范围,输出一种情况. 限制: 1 <= n <= 600 思路: 贪心:能匹配的先匹配. 括号匹配问题,果断先思考用栈能不能做. C++ Code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 3

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

题目链接:点击打开链接 题意:给你一个长度为m的只含()的括号串s, 要求在s两端在加两个串p和q, 使得总长度为n,并且平衡, 平衡是指任意前缀串的(都不少于), 并且整个串的(和)一样多. 思路:我们不难想到这样一个DP, d[i][j]表示长度为i的串,(比)多j个(或者)比(多j个, 是等价的)的方案数.  那么转移很简单: if(j > 0) d[i][j] += d[i-1][j-1] ;    d[i][j] += d[i-1][j+1]. 然后为了满足那两个条件, 我们计算出s串

codeforces 552 E Vanya and Brackets

题意是这样,给出一个运算符只有+跟*,数字都在1到9之间的算式,要你加入一对括号,使得算式的结果尽可能的大,保证最多十五个乘号. 很显然,若要让加入的括号能够影响原本运算的结果,必然是要影响乘法,那么加入的这对括号中必然至少有一个跟乘号是相邻的,恰好乘号的数目很小,那么直接枚举括号的位置即可,每次算出当前解更新ans即可. #include<map> #include<string> #include<cstring> #include<cstdio> #i

codeforces E. Famil Door and Roads 期望

一棵树,n个节点,边长为1,有q个询问,每个询问给出u,v(u != v),问在树上等概率加一条边,如果使得u,v在一个环内,则这种加边方式是合法的,此时的值为环的长度,所有合法的加边方式出现的概率相等,问值的期望. 2 <= n,m <= 10^5 对于u,v原来路径上的边一定在环内,贡献为1,新加的边也一定在环内,贡献为1,求其余的边的贡献就行了 分2种情况考虑: 1.lca(u,v) 不等于u 和 v 2.lca(u,v) 为u 或者 v 代码: //File Name: cf629E.

CodeForces 149D 区间DP Coloring Brackets

染色有三个条件: 对于每个点来说要么不染色,要么染红色,要么染蓝色 对于每对配对的括号来说,有且只有一个一边的括号被染色 相邻的括号不能染成相同的颜色 首先可以根据给出的括号序列计算出括号的配对情况,具体来说就是第i个括号与R[i]个括号配对. 对于一个正规配对括号序列(correct bracket sequence),d(l, r, c1, c2)表示括号序列S[i]~S[j],i左边括号的颜色是c1,r右边的括号颜色是c2(0表示没有染色),这样的序列的染色方法数. 与S[i]配对的可能是

codeforces 的20道C题

A - Warrior and Archer CodeForces - 595C n  偶数  然后n个数字 A B 轮流取一个 A让差变小B让差变大 直到最后2 个   求的是最小剩下的差 最后剩下的 L R  相距 n/2    求一下最小的就行 #include <iostream> #include <cstdio> #include <cmath> #include <map> #include <algorithm> #include

Codeforces 629 E. Famil Door and Roads

题目链接:http://codeforces.com/problemset/problem/629/E 询问这个简单环的期望.考虑将这个环拆成两部分. 令${deep[x]>=deep[y]}$,${size[x]}$表示以$x$为根的子树大小,${sdown[x]}$示以$x$为根的子树的所有节点到$x$的距离和,${sall[x]}$所有点到$x$的距离和.${ne}$表示从${y-->x}$路径上${y}$的儿子. 1.${dis(x,y)}$这是一个环肯定要经过的,算入答案. 2.分情

codeforces 149D - Coloring Brackets (区间dp)

题目大意: 给出一组合法的括号. 括号要么不涂颜色,要么就涂上红色或者绿色. 匹配的括号只能有一个有颜色. 两个相邻的括号不能有相同的颜色. 思路分析: 因为是一个合法的括号序列. 所以每个括号与之匹配的位置是一定的. 那么就可以将这个序列分成两个区间. (L - match[L] )  (match[L]+1, R) 用递归先处理小区间,再转移大区间. 因为条件的限制,所以记录区间的同时,还要记录区间端点的颜色. 然后就是一个递归的过程. #include <cstdio> #include