HDU 5446 2015长春站网络赛1010(数论模板题)

来源:互联网 发布:通信工程定额软件 编辑:程序博客网 时间:2024/05/19 12:11

这道题知道两个东西就能写出来:lucas+CRT(中国剩余定理),题目很裸。但是有一个坑,就是相乘的时候会爆LL!!!这个时候用一个快速乘就搞定了,这个也是这道题才学会的,其实快速成很简单,就是把一个数变成2进制,然后把*改成了+法(和快速幂基本一样)。
lucas定理: C(n,m) == C(n/p,m/p)*C(n%p,m%p) (mod p) ,p为素数。
证明可以看cxlove大神的博客:lucas定理的证明

下面直接给出AC代码:

**#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>#define LL long long#define FOR(i,x,y)  for(int i = x;i < y;i ++)#define IFOR(i,x,y) for(int i = x;i > y;i --)#define MAXN 110000using namespace std;LL fac[MAXN];//快速幂LL QuickPow(LL a,LL n,LL mod){    LL ans=1;    while(n){        if(n&1) ans = (ans*a)%mod;        a = (a*a)%mod;        n>>=1;    }    return ans;}//快速乘LL Mul(LL a,LL b,LL mod){    LL ret = 0;    while(b){        if(b&1) ret = (ret+a)%mod;        a = (a+a)%mod;        b >>= 1;    }    return ret;}void Get_Fac(LL p){    fac[0] = 1;    for(int i = 1;i <= p;i ++){        fac[i] = fac[i-1]*i;        fac[i] %= p;    }}void Ex_Gcd(LL a,LL b,LL& d,LL& x,LL& y){    if(!b)  {d =a; x = 1; y = 0;}    else { Ex_Gcd(b,a%b,d,y,x); y -= x*(a/b);}}//lucas定理LL Lucas(LL n,LL m,LL p){    LL ret = 1;    while(n && m){        LL a = n%p,b = m%p;        if(a < b)   return 0;        ret = Mul(ret,Mul(fac[a],QuickPow(Mul(fac[a-b],fac[b],p),p-2,p),p),p);        ret %= p;        n /= p;        m /= p;    }    return ret;}//中国剩余定理 x == a[i] (mod m[i])   共有n个方程。LL CRT(LL n,LL* a,LL* m){    LL M = 1,d,y,x = 0;    for(int i = 0;i < n;i ++)   M *= m[i];    for(int i = 0;i < n;i ++){        LL  w = M/m[i];        Ex_Gcd(m[i],w,d,d,y);        x = (x + Mul(y,Mul(w,a[i],M),M)) % M;    }    return (x+M)%M;}int main(){    //freopen("test.in","r",stdin);    int T;    scanf("%d",&T);    while(T--){        LL n,m,num,p[15],a[15];        scanf("%I64d%I64d%I64d",&n,&m,&num);        for(int i = 0;i < num;i ++){            scanf("%I64d",&p[i]);        }        for(int i = 0;i < num;i ++){            Get_Fac(p[i]);            a[i] = Lucas(n,m,p[i]);        }        printf("%I64d\n",CRT(num,a,p));    }    return 0;}**
0 0