大组合数取mod lucas 定理

计算 C(n,m)%p;  这边p是质数 如果不是质数就要麻烦一点

具体的证明不会  只能用那个公式

 

#include<stdio.h>
#include<algorithm>
#include<stdlib.h>
#include<cstring>
#include<string>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<iterator>
#include<stack>

using namespace std;

#define ll   __int64
#define MAXN  500010
#define inf  2000000007
#define mod 1000000007
ll Quick(ll a,ll b,ll c)  //快速幂
{
    ll ans=1;
    a=a%c;
    while(b>0)
    {
        if(b&1)
            ans = (ans*a)%c;
        b>>=1;
        a=(a*a)%c;
    }
    return ans;
} 
ll calc(ll a,ll b,ll c)  这边计算比较小的组合数取mod 如果数组能存下 或者预处理出来每个数的阶乘都能优化一下  只要能算出来就行
{
    if(a<b)
        return 0;
    if(a==b)
        return 1;
    if(b>a-b)
        b=a-b;
    ll ca,cb;
    ca=cb=1;
    for(int i=0;i<b;i++)
    {
        ca=(ca*(a-i))%c;
        cb=(cb*(b-i))%c;
    }
    ll ans = (ca*Quick(cb,c-2,c))%c;   //除法取mod  显然要乘逆元  c是质数的话就能用费马小定理求逆元了
    return ans;

}

ll lucas(ll n,ll m,ll c)
{
    ll ans=1;
    while(n&&m&&ans)
    {
        ans=(ans*calc(n%c,m%c,c))%c;
        n/=c;
        m/=c;
    }
    return ans;
}
int main()
{
    ll n,m,p;
    while(scanf("%I64d%I64d%I64d",&n,&m,&p)!=EOF)
    {
        printf("%I64d\n",lucas(n,m,p));
    }
    return 0;
}

 

posted on 2017-04-04 21:17  HelloWorld!--By-MJY  阅读(202)  评论(0编辑  收藏  举报

导航