CF785D Anton and School - 2 解题报告

CF785D Anton and School - 2

题意:给定一个长度\(\le 2 \times 10e5\)由'('和')'组成的字符串,问有多少个子串(可以不连续),前半部分是由\('('\)组成后半部分由\(')'\)组成.


考虑枚举每一个可能的字串的中间,然后统计两边

先预处理每一个位置前面有多少个\('('\),后面有多少个\(')'\)

然后枚举每一个\('('\)表示中间且必选

设当前位(包括)有\(a\)\('('\)
则对此位置的答案即为\(\sum_{i=0}^{min(a-1,b-1)} C_{a-1}^i \times C_b^{i+1}\)

引理:范德蒙恒等式,\(\sum_{i=0}^k C_a^i \times C_b^{k-i}=C_{a+b}^k\)

对上式进行化简即可得 \(C_{a+b-1}^a\)

预处理阶乘和阶乘逆元即可


Code:

#include <cstdio>
#include <cstring>
#define ll long long
const int N=200010;
const ll mod=1e9+7;
ll t[N],f1[N],f2[N],fac[N],inv[N],n,ans;
char c[N];
ll quick_pow(ll d,ll k)
{
    ll f=1;
    while(k)
    {
        if(k&1)
            f=f*d%mod;
        d=d*d%mod;
        k>>=1;
    }
    return f;
}
ll C(ll a,ll b)
{
    if(a>b) return 0;
    if(inv[b-a]==-1) inv[b-a]=quick_pow(fac[b-a],mod-2);
    if(inv[a]==-1) inv[a]=quick_pow(fac[a],mod-2);
    return fac[b]*inv[b-a]%mod*inv[a]%mod;
}
int main()
{
    memset(inv,-1,sizeof(inv));
    scanf("%s",c);
    n=strlen(c);
    for(int i=0;i<n;i++)
        t[i+1]=(c[i]==')');
    for(int i=1;i<=n;i++)
        f1[i]=f1[i-1]+!t[i];
    for(int i=n;i;i--)
        f2[i]=f2[i+1]+t[i];
    fac[0]=1;
    for(int i=1;i<=n;i++)
        fac[i]=fac[i-1]*i%mod;
    for(int i=1;i<=n;i++)
        if(!t[i])
        {
            ll a=f1[i],b=f2[i];
            (ans+=C(a,a+b-1))%=mod;
        }
    printf("%lld\n",ans);
    return 0;
}


2018.7.19

posted @ 2018-07-19 19:53  露迭月  阅读(399)  评论(0编辑  收藏  举报