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
题解:很明显可以抽象成卡特兰数的表达式,即从(0,0)点走到(n,m)点,但是不能越过y=x这条线的方案数,方案数为**$C_{n+m}^{m}-C_{n+m}^{m-1}$;
我用了两个做法。。先是用逆元做了一次,有用Lucas定理做了一次,直接把组合数化简/套用定理+快速幂即可.
逆元代码:(写得丑就这么看吧……应该能看懂)
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 using namespace std; 5 const int MAXN=1000001; 6 const long long mod=20100403; 7 long long tot=1,temp=1; 8 long long ksm(long long a,long long b,long long c) 9 { 10 long long ans=1; 11 while(b!=0) 12 { 13 if(b%2==1) ans=ans*a%c; 14 a=a*a%c; 15 b/=2; 16 } 17 return ans%c; 18 } 19 int main(int argc, char *argv[]) 20 { 21 long long n,m,i,j,nn,mm; 22 scanf("%lld%lld",&n,&m); 23 nn=n,mm=n; 24 for(i=n+m;i>n;i--) 25 tot=tot*i%mod; 26 for(i=1;i<=m;i++) 27 temp=temp*i%mod; 28 long long k=ksm(temp,mod-2,mod); 29 tot=tot*k%mod; 30 temp=1; 31 for(i=n+m;i>=n+2;i--) 32 temp=temp*i%mod; 33 long long tempt=1; 34 for(i=1;i<m;i++) 35 tempt=tempt*i%mod; 36 k=ksm(tempt,mod-2,mod); 37 tot=(tot-k*temp%mod+mod)%mod; 38 printf("%lld\n",tot); 39 return 0; 40 }
Lucas代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int mod=20100403; 6 long long n,m,p; 7 long long quick_pow(long long a,long long b,long long c) 8 { 9 long long ans=1; 10 while(b!=0) 11 { 12 if(b%2==1) ans=ans*(a%c)%c; 13 a=a%c*a%c; 14 b/=2; 15 } 16 if(b==0) return ans%c; 17 } 18 long long C(long long n,long long m,long long p) 19 { 20 long long a=1,b=1; 21 if(m>n) return 0; 22 while(m>0) 23 { 24 a=a*n%p; 25 b=b*m%p; 26 m--; 27 n--; 28 } 29 return a*quick_pow(b,p-2,p)%p; 30 } 31 long long Lucas(long long n,long long m,long long p) 32 { 33 if(m==0) return 1; 34 return (C(n%p,m%p,p)*Lucas(n/p,m/p,p)%p); 35 } 36 int main(int argc, char *argv[]) 37 { 38 scanf("%d%d",&n,&m); 39 long long ans=Lucas(n+m,m,mod); 40 ans=(ans-Lucas(n+m,m-1,mod)+mod)%mod; 41 printf("%lld\n",ans); 42 return 0; 43 }
叶子的离去,是风的追求,还是树的不挽留?