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这条线的方案数,方案数为Cmn+mCm1n+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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章