BZOJ1856:[SCOI2010]字符串(卡特兰数,组合数学)
Description
lxhgww最近接到了一个生成字符串的任务,任务需要他把n个1和m个0组成字符串,但是任务还要求在组成的字符串中,在任意的前k个字符中,1的个数不能少于0的个数。现在lxhgww想要知道满足要求的字符串共有多少个,聪明的程序员们,你们能帮助他吗?
Input
输入数据是一行,包括2个数字n和m
Output
输出数据是一行,包括1个数字,表示满足要求的字符串数目,这个数可能会很大,只需输出这个数除以20100403的余数
Sample Input
2 2
Sample Output
2
HINT
【数据范围】
对于30%的数据,保证1<=m<=n<=1000
对于100%的数据,保证1<=m<=n<=1000000
Solution
只要看懂这个博客方法二的证明,就可以发现这个题只不过是那个证明变了一点而已。
只需要做起点的对称点用总路径减去不合法路径即可。
最后答案是C(m+n,n)-C(m+n,n+1)
Code
1 #include<iostream> 2 #include<cstdio> 3 #define N (2000000+1000) 4 #define MOD (20100403) 5 using namespace std; 6 long long n,m,Fact[N],FactInv[N],Inv[N],ans; 7 8 long long C(long long n,long long m) 9 { 10 if (m>n) return 0; 11 return Fact[n]*FactInv[m]%MOD*FactInv[n-m]%MOD; 12 } 13 14 int main() 15 { 16 scanf("%lld%lld",&n,&m); 17 Inv[0]=Inv[1]=Fact[0]=Fact[1]=1; 18 for (int i=2; i<=m+n; ++i) 19 { 20 Fact[i]=Fact[i-1]*i%MOD; 21 Inv[i]=(MOD-MOD/i)*Inv[MOD%i]%MOD; 22 } 23 24 FactInv[0]=1; 25 for (int i=1; i<=m+n; ++i) 26 FactInv[i]=Inv[i]*FactInv[i-1]%MOD; 27 printf("%lld",((C(m+n,n)-C(m+n,n+1))%MOD+MOD)%MOD); 28 }