• Codeforces 785D


    题目链接:https://codeforces.com/problemset/problem/785/D

    题解:

    首先很好想的,如果我们预处理出每个 "(" 的左边还有 $x$ 个 "(",以及右边有 $y$ 个 ")",那么就有式子如下:

      ① 若 $x+1 le y$:$C_{x}^{0} C_{y}^{1} + C_{x}^{1} C_{y}^{2} + cdots + C_{x}^{x} C_{y}^{x+1} = sum_{i=0}^{x} C_{x}^{i} C_{y}^{i+1}$

      ② 若 $x+1 > y$:$C_{x}^{0} C_{y}^{1} + C_{x}^{1} C_{y}^{2} + cdots + C_{x}^{y-1} C_{y}^{y} = sum_{i=0}^{y-1} C_{x}^{i} C_{y}^{i+1}$

    然后算一下,哦哟 $O(n^2)$ 的优秀算法,GG,想了半天也不知道咋优化,看了题解才知道是“范德蒙德恒等式”:

    $sum_{i=0}^{r} C_{m}^{i} C_{n}^{r-i} = C_{m+n}^{r}$

    以及它的一个推导等式

    $sum_{i=0}^{m} C_{m}^{i} C_{n}^{r+i} = C_{m+n}^{m+r}$

    ① 直接用推导等式可以得到:

    $sum_{i=0}^{x} C_{x}^{i} C_{y}^{i+1} = C_{x+y}^{x+1}$

    而 ② 则用范德蒙德恒等式得到:

    $sum_{i=0}^{y-1} C_{x}^{i} C_{y}^{i+1} = sum_{i=0}^{y-1} C_{x}^{i} C_{y}^{y-1-i} = C_{x+y}^{y-1}$

    综上,就变成了:对于每个 "(",假设其左边还有 $x$ 个 "(",右边有 $y$ 个 ")",那么对于答案的贡献:

      ① 若 $x+1 le y$,则为 $C_{x+y}^{x+1}$

      ② 若 $x+1 > y$,则为 $C_{x+y}^{y-1}$

    只要预处理出阶乘和阶乘的逆元,那么每次算 $C_{n}^{r}$ 就是 $O(1)$ 的。

     

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=1e9+7;
    const int maxn=2e5+10;
    
    char s[maxn];
    int n,x[maxn],y[maxn];
    
    ll fpow(ll a,ll n)
    {
        ll res=1, base=a%mod;
        while(n)
        {
            if(n&1) res*=base, res%=mod;
            base*=base, base%=mod;
            n>>=1;
        }
        return res%mod;
    }
    ll inv(ll a){return fpow(a,mod-2);}
    
    ll fac[maxn],fac_inv[maxn];
    ll C(ll n,ll r)
    {
        ll res=fac[n];
        res*=fac_inv[r], res%=mod;
        res*=fac_inv[n-r], res%=mod;
        return res;
    }
    
    int main()
    {
        fac[0]=1, fac_inv[0]=inv(fac[0]);
        for(int i=1;i<maxn;i++) fac[i]=fac[i-1]*i%mod, fac_inv[i]=inv(fac[i]);
    
        scanf("%s",s+1), n=strlen(s+1);
    
        x[1]=0;
        for(int i=2;i<=n;i++) x[i]=x[i-1]+(s[i-1]=='(');
        y[n]=0;
        for(int i=n-1;i>0;i--) y[i]=y[i+1]+(s[i+1]==')');
        //for(int i=1;i<=n;i++) printf("%d %d
    ",x[i],y[i]);
    
        ll ans=0;
        for(int i=1;i<=n;i++)
        {
            if(s[i]!='(') continue;
            if(y[i]<=0) continue;
            if(x[i]+1<=y[i])
                ans+=C(x[i]+y[i],x[i]+1), ans%=mod;
            else
                ans+=C(x[i]+y[i],y[i]-1), ans%=mod;
        }
        cout<<ans<<endl;
    }
  • 相关阅读:
    【转】Java抽象类与接口的区别
    【转】java方法参数传递方式--按值传递、引用传递
    关联mysql失败_Server returns invalid timezone. Go to 'Advanced' tab and set 'serverTimezon'
    分词器的安装与使用
    Mysql、ES 数据同步
    ES、kibana安装及交互操作
    tl-wr742n 怎么设置dns
    tl-wr742n无线路由器怎么设置
    PowerMock学习(十一)之Mock private methods的使用
    PowerMock学习(十)之Mock spy的使用
  • 原文地址:https://www.cnblogs.com/dilthey/p/10692881.html
Copyright © 2020-2023  润新知