zoukankan      html  css  js  c++  java
  • 【23.24%】【codeforces 629C】Famil Door and Brackets

    time limit per test2 seconds
    memory limit per test256 megabytes
    inputstandard input
    outputstandard output
    As Famil Door’s birthday is coming, some of his friends (like Gabi) decided to buy a present for him. His friends are going to buy a string consisted of round brackets since Famil Door loves string of brackets of length n more than any other strings!

    The sequence of round brackets is called valid if and only if:

    the total number of opening brackets is equal to the total number of closing brackets;
    for any prefix of the sequence, the number of opening brackets is greater or equal than the number of closing brackets.
    Gabi bought a string s of length m (m ≤ n) and want to complete it to obtain a valid sequence of brackets of length n. He is going to pick some strings p and q consisting of round brackets and merge them in a string p + s + q, that is add the string p at the beginning of the string s and string q at the end of the string s.

    Now he wonders, how many pairs of strings p and q exists, such that the string p + s + q is a valid sequence of round brackets. As this number may be pretty large, he wants to calculate it modulo 109 + 7.

    Input
    First line contains n and m (1 ≤ m ≤ n ≤ 100 000, n - m ≤ 2000) — the desired length of the string and the length of the string bought by Gabi, respectively.

    The second line contains string s of length m consisting of characters ‘(’ and ‘)’ only.

    Output
    Print the number of pairs of string p and q such that p + s + q is a valid sequence of round brackets modulo 109 + 7.

    Examples
    input
    4 1
    (
    output
    4
    input
    4 4
    (())
    output
    1
    input
    4 3
    (((
    output
    0
    Note
    In the first sample there are four different valid pairs:

    p = “(“, q = “))”
    p = “()”, q = “)”
    p = “”, q = “())”
    p = “”, q = “)()”
    In the second sample the only way to obtain a desired string is choose empty p and q.

    In the third sample there is no way to get a valid sequence of brackets.

    【题解】

    给你一个串;
    只包含圆括号;
    可以让你在最左边和最右边加上两个串p和q;
    这两个串也只能包括括号;
    要使得最后的括号是匹配的;
    问你有多少对P和q,p和q可以为空
    每时每刻左括号的数目都要大于等于右括号的数目;
    最后那个限制起了很大的作用;
    把左括号看做1,右括号看做-1;
    则它的要求是每时每刻前缀和都大于0;
    则先求出所给的s的前缀和,并记录前缀和的最小值mi;
    预处理出dp[i][j]表示i个括号能够造出前缀和为j的方案数(满足每时每刻前缀和都大于等于0的方案);
    然后枚举q的长度i,前缀和为j
    如果dp[i][j]+mi>=0;
    则从左到中间那个串都是满足题意的了(前缀和始终大于等于0)
    然后再获取P;
    p的长度就是n-m-i;
    它的前缀和该是啥?j+pres;
    这里的j+pres指的是负数->加上dp[n-m-i][j+pres];
    可以理解为从右到左进行DP;然后从右到左的过程中每时每刻右括号的数目都大于左括号的数目;(等价转化);
    这样可以保证从最左边的q到最右边的p的过程中间都不会出现前缀和小于0的情况;
    假设在p处出现了前缀和小于0;则在这个位置的右边右括号的数目大于左括号的数目;最后结果就不可能为0;只可能是负数;
    这和j+pres-(j+pres)==0不符合;
    所以在这个串中不会出现前缀和为负数的情况;
    具体实现看代码;
    (那个DP很简单的。。);

    #include <cstdio>
    #include <cmath>
    #include <set>
    #include <map>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    #include <vector>
    #include <stack>
    #include <string>
    #define LL long long
    
    using namespace std;
    
    const int MAXN = 2000;
    const LL MOD = 1e9+7;
    
    int n,m;
    LL dp[MAXN+20][MAXN+20];
    string s;
    
    const int dx[5] = {0,1,-1,0,0};
    const int dy[5] = {0,0,0,-1,1};
    void input_LL(LL &r)
    {
        r = 0;
        char t = getchar();
        while (!isdigit(t)) t = getchar();
        LL sign = 1;
        if (t == '-')sign = -1;
        while (!isdigit(t)) t = getchar();
        while (isdigit(t)) r = r * 10 + t - '0', t = getchar();
        r = r*sign;
    }
    
    void input_int(int &r)
    {
        r = 0;
        char t = getchar();
        while (!isdigit(t)) t = getchar();
        int sign = 1;
        if (t == '-')sign = -1;
        while (!isdigit(t)) t = getchar();
        while (isdigit(t)) r = r * 10 + t - '0', t = getchar();
        r = r*sign;
    }
    
    
    int main()
    {
        //freopen("F:\rush.txt", "r", stdin);
        input_int(n);input_int(m);
        cin >> s;
        int pres = 0,mi=0;
        for (int i = 0;i<=m-1;i++)
            {
                if (s[i]=='(')
                    pres++;
                else
                    pres--;
                mi = min(mi,pres);
            }
        dp[0][0] = 1;
        for (int i = 1;i <= 2000;i++)
            for (int j = 0;j <= i;j++)
            {
                if (j)
                    dp[i][j]=(dp[i][j]+dp[i-1][j-1])%MOD;//add "("
                dp[i][j] = (dp[i][j]+dp[i-1][j+1]) % MOD;//add ")"
            }
    
        LL ans = 0;
        for (int p = 0;p <= n-m;p++)
            for (int j = 0;j <= p;j++)
                if (mi+j>=0 && j+pres<=(n-m))
                    ans = (ans + dp[p][j]*dp[n-m-p][pres+j])%MOD;
        cout << ans << endl;
        return 0;
    }
    
  • 相关阅读:
    JS 实现图片模态框,幻灯片,跑马灯功能
    JavaScript 实现表格单列按字母排序
    JavaScript 进度条重复加载
    JS / CSS 实现的便签记录本
    HTML CSS, JavaScript 计算器
    JS/CSS 各种操作信息提示效果
    JS/CSS 在屏幕底部弹出消息
    Immer 实战讲解
    mixin配合class实现多继承的绝佳妙用
    Axios源码深度剖析
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7632113.html
Copyright © 2011-2022 走看看