题目描述
lxhgww最近接到了一个生成字符串的任务,任务需要他把n个1和m个0组成字符串,但是任务还要求在组成的字符串中,在任意的前k个字符中,1的个数不能少于0的个数。现在lxhgww想要知道满足要求的字符串共有多少个,聪明的程序员们,你们能帮助他吗?
输入输出格式
输入格式:
输入数据是一行,包括2个数字n和m
输出格式:
输出数据是一行,包括1个数字,表示满足要求的字符串数目,这个数可能会很大,只需输出这个数除以20100403的余数
输入输出样例
说明
limitation
每点2秒
对于30%的数据,保证1<=m<=n<=1000
对于100%的数据,保证1<=m<=n<=1000000
来源:SCOI 2010
一道卡特兰数的变式。类似的,受卡特兰数的启发,我们仍然把1看成出栈操作,0看成入栈操作。在不考虑合法性的情况下我们有C(n + m, n) 种方法。又类似的,我们对一个不合法的情况,考虑从前往后第一次取到1比0多1个的时候,我们把前面的1,0取反,这时我们会得到一个有n - 1个1、m + 1个0的序列,而且枚举取反后的序列一定和操作前的序列一一对应。那么不合法序列共有C(n + m, n - 1)种。这个时候我们就可以线性递推组合数做这道题了(PS:快速幂求逆元好写多了呀)。
#include<cstdio>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
int n, m;
LL ans[2];
const LL mod = 20100403;
LL fpow(LL a, LL b, LL p) {
LL ans = 1;
while(b) {
if(b & 1) ans = (ans * a) % p;
a = (a * a) % p;
b >>= 1;
}
return ans % p;
}
void count(int a, int b) {
for(register int i = 1; i < b; ++i) {
ans[0] = ans[1];
(ans[1] *= (fpow(i + 1, mod - 2, mod) * (a - i)) % mod) %= mod;
}
}
int main() {
scanf("%d%d", &n, &m);
if(n < m) {
putchar('0');
return 0;
}
const int down = n + m;
ans[0] = 1, ans[1] = down;
count(down, m);
LL res = ans[1] - ans[0] >= 0 ? ans[1] - ans[0] : ans[1] - ans[0] + mod;
printf("%d", res);
return 0;
}
rockdu
没有帐号? 立即注册