Codeforces Round #404 D. Anton and School - 2 (范德蒙恒等式+逆元求组合数)

D. Anton and School - 2

题意

给定一个字符串 s ,只含有字符 ( 和 )。问 s 有多少个子序列(可以不连续) sub ,满足如下条件:

  • sub 不为空串
  • sub 为偶数长度
  • sub 串的前半串均为 (
  • sub 串的后半串均为 )

思路

官方题解是推导出一个容易求解的同等情况,比较容易想到的是对于每个左括号,求得前面的左括号个数以及后面的右括号个数,求组合数相乘累加.
直接复制了一份题解
这里写图片描述
这里写图片描述

代码

#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i=a;i<b;i++)
const int INF=0x3f3f3f3f;
const int maxn=2e5+50;
const int mod=1e9+7;
const double PI=acos(-1);
typedef long long ll;
typedef unsigned int ui;
using namespace std;

char buf[maxn];
int cl[maxn],cr[maxn];
const char LB='(',RB=')';

//逆元+阶乘打表直接求组合数
ll fac[maxn];
ll inv(ll a){
    return(a==1?1:inv(mod%a)*(mod-mod/a)%mod);
}
void init(int Mod){
    fac[0]=1;
    for(int i=1;i<maxn;i++){
        fac[i]=(fac[i-1]*i)%Mod;
    }
}

ll C(int n,int m){
    ll ret=fac[n];
    ret=(ret*inv(fac[m])%mod)*inv(fac[n-m])%mod;
    return ret;
}

int main()
{
#ifndef ONLINE_JUDGE
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
#endif
    init(mod);
    //int n,m;
    //while(cin>>n>>m ) cout<<C(n,m)<<endl;
    while(~scanf(" %s",buf+1))
    {
        int len=strlen(buf+1);
        cl[0]=cr[0]=0;
        for(int i=1;i<=len;i++) {
            char c=buf[i];
            if(c==LB) cl[i]=cl[i-1]+1;
            else cl[i]=cl[i-1];
            if(c==RB) cr[i]=cr[i-1]+1;
            else cr[i]=cr[i-1];
        }
        ll ans=0;
        for(int i=1;i<=len;i++){
            char c=buf[i];
            if(c==LB){
                int tll=cl[i-1],tr=cr[len]-cr[i],tl=cl[i];
                ans=(ans+C(tl+tr,min(tl,tr)))%mod;
                ans=(ans-C(tll+tr,min(tll,tr))+mod)%mod;
                //cout<<i<<" left "<<tl<<" "<<tll<<" right "<<tr<<endl;
                //cout<<i<<" "<<ans<<endl;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值