组合数学——Codeforces Round #404 (Div. 2) D. Anton and School - 2

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

  • 题意:给出一个只含有 ‘(’ 和 ‘)’ 的字符串,求其中含有多少个RSBS子序列。RSBS定义为:不为空,长度为偶数,前一半全是’(‘,后一半全是’)’

  • 分析:一个很显然的思路就是枚举每一个左括号作为中间分隔点,然后用组合数计算不同长度的RSBS的和: N1i=0CiNCi+1M=N1i=0CiNCMi1M=CM1N+M 这样就可以 O(N) 计算出结果了

  • AC代码:

/*************************************************************************
    > File Name: test.cpp
    > Author: Akira 
    > Mail: qaq.febr2.qaq@gmail.com 
 ************************************************************************/

#include <iostream>
#include <sstream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <bitset>
#include <queue>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <set>
#include <list>
#include <ctime>
#include <climits>
typedef long long LL;
typedef unsigned long long ULL;
typedef long double LD;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define Sqr(a) ((a)*(a))
using namespace std;

#define MaxN 100001
#define MaxM MaxN*10
#define INF 0x3f3f3f3f
#define PI 3.1415926535897932384626
const int mod = 1E9+7;
const double eps = 1e-6;
#define bug cout<<88888888<<endl;
#define debug(x) cout << #x" = " << x << endl;
const int SIZE = 400001;
const int P = mod;
LL f[SIZE], v[SIZE];
LL rev[SIZE];
LL rp(LL now, int k) 
{
    LL will = 1;
    for (; k; k >>= 1, now *= now, now %= P) 
    {
        if (k & 1) will *= now, will %= P;
    }
    return will;
}
LL C(int n, int m) 
{
    if(n < m) return 0;
    return f[n]*rev[m]%P*rev[n-m]%P;
}
void init()
{
    f[0] = 1; v[0] = 1;
    rev[0] = 1;
    for (int i = 1; i <= SIZE; i++) //1e6以内的组合数
    {
        f[i] = f[i - 1] * i % P;
        rev[i] = rp(f[i], P-2);
    }
}
char str[200005];
int main() 
{
    init();
    scanf("%s", str);
    int Left = 0, Right = 0;
    int len = strlen(str); 
    for(int i=0;i<len;i++) if(str[i]=='(')Left++; else Right++;
    LL L=0,R=Right,ans = 0;
    for(int i=0;i<len;i++)
    {
        if(!Right) break;
        if(str[i]=='(')  L++,ans+=C(L-1+R,R-1);
        else R--;
        if(ans>mod) ans%=mod;
    }
    printf("%lld\n",ans);
    //system("pause");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值