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

题意: 左边全为 '(' 右边全为 ')' 且两者数量想等的字符串称为 RSBS. 给出一个由 '(' 和 ')' 组成的字符串, 问其有多少子序列是 RSBS.

思路: 可以先预处理一下, 用 a[i] 记录 i 前面(包括 i 这个位置)的 '(' 的数目, b[i] 记录 i 后面(包括 i 这个位置)的 ')' 的数目, 然后从左往右枚举以 '(' 结尾的情况,

那么当前情况下的 RSBS 数目为:

C(a[i] - 1, 0) * C(b[i], 1) + C(a[i] - 1, 1) * C(b[i], 2) + C(a[i] - 1, 2) * C(b[i], 3) + ...

= ∑min(a-1, b-1)0  C(a - 1, x) * C(b, x + 1)

= ∑min(a-1, b-1)0  C(a - 1, a - 1 - x) * C(b, x + 1)

= C(a - 1 + b, a) (范德蒙恒等式)

然后将所有情况的 RSBS 数目累加一下就好啦.

注意这里的组合数比较大, 取模的话需要用到 exgcd 或者 快速幂.

代码1: 快速幂求组合数取模 C(n, m) % mode = (n! % mode) * get_pow((n - m)! * m! % mode, mode - 2) % mode. (这个公式能通过费马小定理变换得到).

 #include <iostream>
#define ll long long
using namespace std; const int mode = 1e9 + ;
const int MAXN = 2e5 + ;
ll a[MAXN], b[MAXN], gel[MAXN];
string s; ll get_pow(ll x, int n){
ll ans = ;
while(n){
if(n & ) ans = ans * x % mode;
x = x * x % mode;
n >>= ;
}
return ans;
} int main(void){
ll ans = ;
cin >> s;
if(s[] == '(') a[] = ;
for(int i = ; i < s.size(); i++){
if(s[i] == '(') a[i] = a[i - ] + ;
else a[i] = a[i - ];
}
for(int i = s.size() - ; i >= ; i--){
if(s[i] == ')') b[i] = b[i + ] + ;
else b[i] = b[i + ];
}
gel[] = ;
for(int i = ; i < MAXN; i++){
gel[i] = gel[i - ] * i % mode;
}
for(int i = ; i < s.size(); i++){
if(s[i] == ')') continue;
ll cnt1 = a[i], cnt2 = a[i] + b[i] - ;
ans = (ans + (gel[cnt2] * get_pow(gel[cnt1] * gel[cnt2 - cnt1] % mode, mode - )) % mode) % mode;
}
cout << ans << endl;
return ;
}

代码2: 用乘法逆元求得组合数取模

 #include <iostream>
#define ll long long
using namespace std; const int mode = 1e9 + ;
const int MAXN = 2e5 + ;
ll a[MAXN], b[MAXN], gel[MAXN];
string s; void exgcd(ll a, ll b, ll &x, ll &y){
if(!b){
y = ;
x = ;
return;
}
exgcd(b, a % b, y, x);
y -= a / b * x;
} int main(void){
ll ans = ;
cin >> s;
if(s[] == '(') a[] = ;
for(int i = ; i < s.size(); i++){
if(s[i] == '(') a[i] = a[i - ] + ;
else a[i] = a[i - ];
}
for(int i = s.size() - ; i >= ; i--){
if(s[i] == ')') b[i] = b[i + ] + ;
else b[i] = b[i + ];
}
gel[] = ;
for(int i = ; i < MAXN; i++){
gel[i] = gel[i - ] * i % mode;
}
for(int i = ; i < s.size(); i++){
if(s[i] == ')') continue;
ll cnt1 = a[i], cnt2 = a[i] + b[i] - ;
ll cc1 = gel[cnt2], cc2 = gel[cnt2 - cnt1] * gel[cnt1] % mode;
ll x, y;
exgcd(cc2, mode, x, y);
x = (x % mode + mode) % mode;
ans = (ans + (cc1 * x) % mode) % mode; }
cout << ans << endl;
return ;
}

cf785D(组合数学)的更多相关文章

  1. poj 3734 Blocks 快速幂+费马小定理+组合数学

    题目链接 题意:有一排砖,可以染红蓝绿黄四种不同的颜色,要求红和绿两种颜色砖的个数都是偶数,问一共有多少种方案,结果对10007取余. 题解:刚看这道题第一感觉是组合数学,正向推了一会还没等推出来队友 ...

  2. 组合数学or not ---- n选k有重

    模板问题: 1. 取物品 (comb.pas/c/cpp) [问题描述] 现在有n个物品(有可能相同),请您编程计算从中取k个有多少种不同的取法.[输入] 输入文件有两行,第一行包含两个整数n,k(2 ...

  3. 组合数学(全排列)+DFS CSU 1563 Lexicography

    题目传送门 /* 题意:求第K个全排列 组合数学:首先,使用next_permutation 函数会超时,思路应该转变, 摘抄网上的解法如下: 假设第一位是a,不论a是什么数,axxxxxxxx一共有 ...

  4. uestc1888 Birthday Party    组合数学,乘法原理

    题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=25539#problem/G 题目意思: 有n个人,每个人有一个礼物,每个人能拿 ...

  5. UVA 11076 Add Again 计算对答案的贡献+组合数学

    A pair of numbers has a unique LCM but a single number can be the LCM of more than one possiblepairs ...

  6. POJ3252——Round Number(组合数学)

    Round Numbers DescriptionThe cows, as you know, have no fingers or thumbs and thus are unable to pla ...

  7. HDU4675【GCD of scequence】【组合数学、费马小定理、取模】

    看题解一开始还有地方不理解,果然是我的组合数学思维比较差 然后理解了之后自己敲了一个果断TLE.... 我以后果然还得多练啊 好巧妙的思路啊 知识1: 对于除法取模还需要用到费马小定理: a ^ (p ...

  8. hdu 4810 Wall Painting (组合数学+二进制)

    题目链接 下午比赛的时候没有想出来,其实就是int型的数分为30个位,然后按照位来排列枚举. 题意:求n个数里面,取i个数异或的所有组合的和,i取1~n 分析: 将n个数拆成30位2进制,由于每个二进 ...

  9. CCF 201312-4 有趣的数 (数位DP, 状压DP, 组合数学+暴力枚举, 推公式, 矩阵快速幂)

    问题描述 我们把一个数称为有趣的,当且仅当: 1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次. 2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前. 3. 最高 ...

随机推荐

  1. window操作常识

  2. FileInputStream 原理总结 把文件作为字节流进行读操作

    package io; import java.io.FileInputStream; import java.io.IOException; public class IOUtil { /** * ...

  3. 通俗解释glLoadIdentity(),glPushMatrix(),glPopMatrix()的作用

    通俗解释glLoadIdentity(),glPushMatrix(),glPopMatrix()的作用 (2012-04-02 09:17:28) 转载▼   对于glLoadIdentity(), ...

  4. UVA-11020(BST)

    题意: 给n个点,一个点(x,y)有优势时满足不存在点(fx,fy)使得fx<x,fy<=y或fx<=x,fy<y;问当前有多少个有优势点; 思路: 学习BST的入门题,代码是 ...

  5. 【二叉树的递归】05二叉树中找任意起点和终点使他们的路径和最大【Binary Tree Maximum Path Sum】

    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 给定一个二叉树,寻找值最大的路径. ...

  6. C语言小程序(四)、杨辉三角

    输入要显示的杨辉三角的行数,会打印出金字塔型的杨辉三角,不过行数太多的话,效果不太好,可以再调整一下格式控制. #include <stdio.h> #include <stdlib ...

  7. LiveMediaStreamer

    LiveMediaStreamer is an open source multimedia framework that allows the manipulation of multiple au ...

  8. java枚举学习enum

    java 1.5以后才出现enum的关键字 所有的enum类都继承自Enum类,所以enum类无法再继承其他的类,可以实现接口,枚举类出了不能被继承其余的与普通类的特性一致, 枚举类的构造函数只能自己 ...

  9. Azure 用户自定义路由 (User Defined Route)

    在公有云环境中,用户创建了一个Vnet,添加了若干个网段后,这几个网段是全联通的状态. 如果希望在Vnet中添加一些功能性的设备,比如防火墙.IPS.负载均衡设备等,就需要进行用户自定义路由的配置. ...

  10. shell入门-grep过滤-1

    正则表达式,就是一个字符串.有一定的规律.我们用指定的字符串匹配一个指定的行.指定的字符串就是正则表达式. 正则表达式有这几个工具:grep egrep sed awk 命令:gerep 说明:过滤出 ...