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 }

 

posted @ 2016-09-02 08:43  BeyondW  阅读(199)  评论(0编辑  收藏  举报