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这条线的方案数,方案数为
Cmn+m−Cm−1n+m
;
我用了两个做法。。先是用逆元做了一次,有用Lucas定理做了一次,直接把组合数化简/套用定理+快速幂即可.
逆元代码:(写得丑就这么看吧……应该能看懂)
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN=1000001;
const long long mod=20100403;
long long tot=1,temp=1;
long long ksm(long long a,long long b,long long c)
{
long long ans=1;
while(b!=0)
{
if(b%2==1) ans=ans*a%c;
a=a*a%c;
b/=2;
}
return ans%c;
}
int main(int argc, char *argv[])
{
long long n,m,i,j,nn,mm;
scanf("%lld%lld",&n,&m);
nn=n,mm=n;
for(i=n+m;i>n;i--)
tot=tot*i%mod;
for(i=1;i<=m;i++)
temp=temp*i%mod;
long long k=ksm(temp,mod-2,mod);
tot=tot*k%mod;
temp=1;
for(i=n+m;i>=n+2;i--)
temp=temp*i%mod;
long long tempt=1;
for(i=1;i<m;i++)
tempt=tempt*i%mod;
k=ksm(tempt,mod-2,mod);
tot=(tot-k*temp%mod+mod)%mod;
printf("%lld\n",tot);
return 0;
}
Lucas代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int mod=20100403;
long long n,m,p;
long long quick_pow(long long a,long long b,long long c)
{
long long ans=1;
while(b!=0)
{
if(b%2==1) ans=ans*(a%c)%c;
a=a%c*a%c;
b/=2;
}
if(b==0) return ans%c;
}
long long C(long long n,long long m,long long p)
{
long long a=1,b=1;
if(m>n) return 0;
while(m>0)
{
a=a*n%p;
b=b*m%p;
m--;
n--;
}
return a*quick_pow(b,p-2,p)%p;
}
long long Lucas(long long n,long long m,long long p)
{
if(m==0) return 1;
return (C(n%p,m%p,p)*Lucas(n/p,m/p,p)%p);
}
int main(int argc, char *argv[])
{
scanf("%d%d",&n,&m);
long long ans=Lucas(n+m,m,mod);
ans=(ans-Lucas(n+m,m-1,mod)+mod)%mod;
printf("%lld\n",ans);
return 0;
}