[SCOI2010]字符串

题目:BZOJ1856、洛谷P1641、codevs2418。

题目大意:给你n个1和m个0,让你用它们组成长度为n+m的串,问有多少串满足,它的任意前缀中的1总是不少于0(答案mod20100403)。

解题思路:这题和字符串一点关系也没有!!

首先我们可以把题目转化为:从0,0走到n+m,n-m,每次可以走(1,1)或(1,-1),求不经过直线y=-1的方案数。

我们先不考虑“不经过直线y=-1”的限制,那么方案数为$C^{m}_{n+m}$。

现在我们考虑不满足条件的方案数,其实就相当于从-2,0走到n+m,n-m的方案数,所以方案数为$C^{m-1}_{n+m}$。

所以答案就为“总方案数-不满足条件的方案数”。

$$egin{align}C^m_{n+m}-C^{m-1}_{n+m}&=&frac{(n+m)!}{n!m!}-frac{(n+m)!}{(n+1)!(m-1)!}\&=&frac{(n+m)!(n+1)-(n+m)!m}{(n+1)!m!}\&=&frac{(n-m+1)(n+m)!}{(n+1)!m!}\&=&(n-m+1)frac{(n+2)(n+3)...(n+m)}{m!}\&=&(n-m+1)(n+2)(n+3)...(n+m)÷1÷2÷...÷mend{align}$$

由于用到取模运算,还要除以1~m,所以需要用到逆元。

既然需要1~m的所有逆元,而且模数是个质数,那就用线性推逆元好了。

可惜的是,在推逆元的时候乘法超int,没有转化为long long,导致没有一发AC。

C++ Code:

#include<cstdio>
using namespace std;
#define p 20100403
int n,m,fact,inv[1000005];
int main(){
	scanf("%d%d",&n,&m);
	int ans=1;
	inv[1]=1;
	for(int i=2;i<=m;++i)
	inv[i]=(long long)(p-p/i)*inv[p%i]%p;
	for(int i=2;i<=m;++i)ans=(long long)ans*(i+n)%p;
	ans=(long long)ans*(n-m+1)%p;
	for(int i=1;i<=m;++i)
	ans=(long long)ans*inv[i]%p;
	printf("%d
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/Mrsrz/p/7381610.html