zoukankan      html  css  js  c++  java
  • [CF785D] Anton and School

    [CF785D] Anton and School - 2

    Description

    给定一个长度≤2×10^5由(和)组成的字符串,问有多少个子串(可以不连续),前半部分是由(组成后半部分由)组成.

    Solution

    枚举最后一个 ( 的位置,枚举选了多少个括号,此时的贡献是 C(ai-1,j)C(bi,j+1)

    这个东西可以转化为 C(ai-1,j) C(bi,bi-j-1),对 j 求和,其实就是 C(ai+bi-1,bi-1)=C(ai+bi-1,ai)

    于是我们暴力枚举 i 然后算组合数即可

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    
    const int mod = 1e9 + 7;
    
    namespace math_mod
    {
        int c__[5005][5005], fac__[3000005];
    
        int qpow(int p, int q)
        {
            return (q & 1 ? p : 1) * (q ? qpow(p * p % mod, q / 2) : 1) % mod;
        }
    
        int inv(int p)
        {
            return qpow(p, mod - 2);
        }
    
        int fac(int p)
        {
            if (p <= 3000000)
                return fac__[p];
            if (p == 0)
                return 1;
            return p * fac(p - 1) % mod;
        }
    
        int __fac(int p)
        {
            return fac(p);
        }
    
        int ncr(int n, int r)
        {
            if (r < 0 || r > n)
                return 0;
            return fac(n) * inv(fac(r)) % mod * inv(fac(n - r)) % mod;
        }
    
        void math_presolve()
        {
            fac__[0] = 1;
            for (int i = 1; i <= 3000000; i++)
            {
                fac__[i] = fac__[i - 1] * i % mod;
            }
            for (int i = 0; i <= 5000; i++)
            {
                c__[i][0] = c__[i][i] = 1;
                for (int j = 1; j < i; j++)
                    c__[i][j] = c__[i - 1][j] + c__[i - 1][j - 1], c__[i][j] %= mod;
            }
        }
    
        int __c(int n, int r)
        {
            if (r < 0 || r > n)
                return 0;
            if (n > 5000)
                return ncr(n, r);
            return c__[n][r];
        }
    }
    
    using namespace math_mod;
    
    const int N = 1e6 + 5;
    string s;
    int a[N], b[N];
    
    signed main()
    {
        ios::sync_with_stdio(false);
        cin >> s;
        s = ' ' + s;
        int n = s.length() - 1;
        for (int i = 1; i <= n; i++)
            a[i] = a[i - 1] + (s[i] == '(');
        for (int i = n; i >= 1; i--)
            b[i] = b[i + 1] + (s[i] == ')');
        math_presolve();
        int ans = 0;
        for (int i = 1; i <= n; i++)
            if (s[i] == '(')
                ans = (ans + __c(a[i] + b[i] - 1, a[i])) % mod;
        cout << ans << endl;
    }
    
  • 相关阅读:
    BZOJ 2154 Crash的数字表格 莫比乌斯反演
    BZOJ 3529 SDOI2014 数表 莫比乌斯反演+树状数组
    bzoj 3527 [Zjoi2014]力
    【bzoj2194】快速傅立叶之二
    bzoj3160 万径人踪灭
    高精度乘法(FFT)
    【网络流24题】太空飞行计划
    奶牛通信
    关于点分治的理解
    0924解题报告
  • 原文地址:https://www.cnblogs.com/mollnn/p/14493742.html
Copyright © 2011-2022 走看看