• 【codeforces 785D】Anton and School


    【题目链接】:http://codeforces.com/contest/785/problem/D

    【题意】

    给你一个长度为n的括号序列;
    让你删掉若干个括号之后,整个序列变成前x个括号为左括号,后x个括号为右括号;
    问你有多少种删除方法.

    【题解】

    先考虑一个简单的问题
    对于一个括号序列,如果前x个括号都是左括号,后y个括号都是右括号;
    ((())))
    那么这个序列的RSBS的个数为C(X+Y,X)
    即相当于构造一个长度为x+y的序列,包含x个1,y个0
    如上述括号序列
    这里写图片描述
    这里即构造一个长度为7的数字序列,里面含有3个1和4个0
    这里选择0对应的左括号和1对应的右括号;
    可以发现它们能够构成满足要求的序列
    如上图的绿色部分;
    这里相当于确定有几个左括号被抵消;
    假如有1个左括号对应的数字是1,那么就相应的有3-1个右括号对应的数字是1;
    这样刚好和两个左括号对应;
    很巧妙的方法吧。
    所以这个序列的答案就是C(7,3)
    当然上面说的是简化版本的问题;
    考虑完整的问题;
    我们可以枚举每一个左括号
    假设这个左括号是最后的RBSB的括号序列的最后一个左括号;
    即这个左括号左边只能是左括号,右边只能是右括号了;

    我们用前缀和处理出这个左括号前面有多少个左括号,这个左括号后面有多少个右括号;
    分别设为x和y;
    瞧;
    这就变成我们刚才所讨论的问题了;
    则答案应该是C(X+Y-1,X),因为这个时候已经确定有一个左括号(即枚举的这个最后一个左括号已经确定了),所以只剩下x+y-1个位置来放那个1了;
    这里X+Y会很大;不能写递推式;
    只能先求出1..200000的阶乘模和对应的乘法逆元;
    然后用C(N,M)=N!/((N-M)!M!)来算

    【完整代码】

    #include <bits/stdc++.h>
    using namespace std;
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define LL long long
    #define rep1(i,a,b) for (int i = a;i <= b;i++)
    #define rep2(i,a,b) for (int i = a;i >= b;i--)
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define rei(x) scanf("%d",&x)
    #define rel(x) scanf("%lld",&x)
    #define ref(x) scanf("%lf",&x)
    
    typedef pair<int, int> pii;
    typedef pair<LL, LL> pll;
    
    const int dx[9] = { 0,1,-1,0,0,-1,-1,1,1 };
    const int dy[9] = { 0,0,0,-1,1,-1,1,-1,1 };
    const double pi = acos(-1.0);
    const int N = 2e5 + 100;
    const LL MOD = 1e9 + 7;
    
    LL fac[N],inv_fac[N],ans;
    int l[N], r[N],n;
    char s[N];
    
    LL ksm(LL x, LL y)
    {
        if (y == 1) return x;
        LL temp = ksm(x, y >> 1);
        temp = (temp*temp)%MOD;
        if (y & 1)
            temp = (temp*x) % MOD;
        return temp;
    }
    
    LL C(LL n, LL m)
    {
        if (n < m) return 0;
        return (((fac[n] * inv_fac[n - m]) % MOD)*inv_fac[m]) % MOD;
    }
    
    int main()
    {
        //freopen("F:\rush.txt", "r", stdin);
        fac[0] = 1, inv_fac[0] = 1;
        rep1(i, 1, 2e5)
            fac[i] = (1LL * fac[i - 1] * i) % MOD, inv_fac[i] = ksm(fac[i], MOD - 2);
        scanf("%s", s + 1);
        n = strlen(s + 1);
        rep1(i, 1, n)
            if (s[i] == '(')
                l[i] = l[i - 1] + 1;
            else
                l[i] = l[i - 1];
        rep2(i, n, 1)
            if (s[i] == ')')
                r[i] = r[i + 1] + 1;
            else
                r[i] = r[i + 1];
        rep1(i,1,n)
            if (s[i] == '(')
            {
                ans = (ans + C(l[i] + r[i] - 1, l[i]))%MOD;
            }
        printf("%lld
    ", ans);
        //printf("
    %.2lf sec 
    ", (double)clock() / CLOCKS_PER_SEC);
        return 0;
    }
  • 相关阅读:
    python之生成器
    Python 类(一)
    Python OOP(面向对象编程)
    python 静态方法、类方法(二)
    记一个有想法没能力实现的产品形态——实时公交
    ubuntu12.04离线安装libjpeg62-dev
    linux内核container_of宏定义分析
    signal函数理解或者void (*signal(int signum,void(*handler)(int)))(int)理解
    HttpServlet cannot be resolved to a type解决方法
    ubuntu12.04不能记住上次编辑位置的解决方案
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7626509.html
Copyright © 2020-2023  润新知