Lucas定理

Lucas定理
适用于大组合数取模。
C(n,m)%p==lucas(n,m,p)==C(n%p,m%p)*lucas(n/p,m/p,p);然后递归调用即可,显然,C(n,0)%p=1;
因为p是质数,这里套用费马小定理,a^(p-1)=1(mod p),a的逆元为a^(p-2),然后套快速幂,预处理阶乘。

 

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<cstring>
#define inf 2147483647
#define For(i,a,b) for(register long long i=a;i<=b;i++)
#define p(a) putchar(a)
#define g() getchar()
//by war
//2017.10.15
using namespace std;
long long n,m,p,t;
long long a[1000010];
void in(long long &x)
{
    long long y=1;
    char c=g();x=0;
    while(c<'0'||c>'9')
    {
    if(c=='-')
    y=-1;
    c=g();
    }
    while(c<='9'&&c>='0')x=x*10+c-'0',c=g();
    x*=y;
}
void o(long long x)
{
    if(x<0)
    {
        p('-');
        x=-x;
    }
    if(x>9)o(x/10);
    p(x%10+'0');
}

long long ksm(long long a,long long b,long long p)
{
    while(b%2==0)
    {
        a*=a;
        a%=p;
        b>>=1;
    }
    long long r=1;
    while(b>0)
    {
        if(b%2==1)
        {
        r*=a;    
        r%=p;
        }
        a*=a;
        a%=p;
        b>>=1;
    }
    return r%p;
}

long long c(long long n,long long m,long long p)
{
    if(m>n)
    return 0;
    return (a[n]%p)*ksm(a[n-m]*a[m],p-2,p)%p;
}

long long lucas(long long n,long long m,long long p)
{
    if(!m)
    return 1;
    return (c(n%p,m%p,p)%p)*lucas(n/p,m/p,p)%p;
}

int main()
{
    in(t);
    while(t--)
    {
    in(n),in(m),in(p);
    a[0]=1;
    For(i,1,(n+m+1))
    a[i]=(a[i-1]*i)%p;
    o(lucas(n+m,m,p)),p('\n');
    }
     return 0;
}

 

posted @ 2017-10-15 21:35  WeiAR  阅读(148)  评论(0编辑  收藏  举报