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