codeforces 785d[补]

题目:http://codeforces.com/problemset/problem/785/D
题目意思:
有一个只有’(‘和’)’的串,可以随意的删除随意多个位置的符号,现在问能构成((((((…((()))))….))))))这种对称的情况有多少种,保证中间对称,左边为’(‘右边为’)’

一道比赛的时候看了一眼,读错题感觉只能做出O(n^2)的前后缀数组的方法,想了几分钟没想出思路去继续搞c。。结果c依然爆炸,后来回去之后又看了看题,太晚了没敢继续敲。。
当时想着思路大概是前后缀数组,然后组合数学。
起床之后推出了这个这里写图片描述
然后有点懵。。这个时间复杂度是O(n^2)的啊,然后。。就没有然后了,默默的看了下题解。。他们公式都是长这样的这里写图片描述
当然,如果 n>m ,对应位置组合数为0,结论不变。 所以C上面那个数为last[i] - 1
为什么呢。。因为我自己组合数学没学好。要通过范德蒙恒等式来进行转换。。弱弱的给个链接http://blog.csdn.net/acdreamers/article/details/31032763
然后,对于阶层,很容易乘爆,而且组合数学是需要除的,所以需要用到乘法逆元,再给个链接。http://blog.csdn.net/daniel_csdn/article/details/50783734

这一道题数学知识涨得很多,很欣慰。

/*
@resouces: codeforces 785D
@date: 2017-3-18
@author: QuanQqqqq
@algorithm: 组合数学 快速幂 前后缀和 费马小 
*/
#include <bits/stdc++.h>

#define ll long long
#define MAXN 200105
using namespace std;

const ll mod = 1e9 + 7;

ll fac[MAXN],nfac[MAXN]; //阶层,阶层的逆元 

ll qsm(ll m,ll n){
    ll ans = 1;
    while(n){
        if(n & 1){
            ans = (ans * m) % mod;
        }
        m = m * m % mod;
        n >>= 1;
    }
    return ans;
} 

void init(){
    fac[0] = fac[1] = 1;
    for(ll i = 2;i < MAXN;i++){
        fac[i] = (i * 1LL * fac[i - 1]) % mod;
    } 
    nfac[MAXN - 1] = qsm(fac[MAXN - 1],mod - 2) % mod;
    for(ll i = MAXN - 2;i >= 0;i--){
        nfac[i] = (nfac[i + 1] * (i + 1)) % mod;
    }
}

ll C(ll n,ll m){
    if(m == 0)
        return 1;
    return fac[n] * nfac[n - m] % mod * nfac[m] % mod;
}

ll pre[MAXN],last[MAXN];
char ch[MAXN];

int main(){
    init();
    scanf("%s",ch + 1); 
    int len = strlen(ch + 1);
    ll p = 0;
    for(int i = 1;i <= len;i++){
        if(ch[i] == '('){
            p++;
        }
        pre[i + 1] = p;
    }
    p = 0;
    for(int i = len;i >= 1;i--){
        if(ch[i] == ')'){
            p++;
        }
        last[i] = p;
    }
    ll ans = 0;
    for(int i = 1;i <= len;i++){
        if(pre[i] && last[i] && ch[i - 1] == '('){
            (ans += C(pre[i] + last[i] - 1,last[i] - 1) % mod) %= mod; 
        }
    }
    printf("%lld\n",ans % mod);
}

记一发阶层逆元的代码

void init(){
    fac[0] = fac[1] = 1;
    for(ll i = 2;i < MAXN;i++){
        fac[i] = (i * 1LL * fac[i - 1]) % mod;
    } 
    nfac[MAXN - 1] = qsm(fac[MAXN - 1],mod - 2) % mod;
    for(ll i = MAXN - 2;i >= 0;i--){
        nfac[i] = (nfac[i + 1] * (i + 1)) % mod;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值