hdu5446 lucas+中国剩余定理

lucas定理 lucas(n,m,p)=C(n%p,m%p,p)*lucas(n/p,m/p,p),p是质数

证明:

 n=ak*p^k+a(k-1)*p^(k-1)+........a0*p^0

m=bk*p^k+b(k-1)*p^(k-1)+........b0*p^0

(1+x)^p=1+x^p (mod p) p是质数  ,可以得到   (1+x)^(p^k)=1+x^(p^k)  (mod p)


(1+x)^n=(1+x)^(ak*p^k)*(1+x)^(ak-1*p^(k-1))*........(1+x)^a0

           =(1+x^(p^k))^ak*(1+x^(p^(k-1)))^ak-1*.........(1+x)^a0

C(n,m)x^m=C(ak,bk)*C(ak-1,bk-1)*.....C(a0,b0);


中国剩余定理:

    a=a1 (mod n1)

    a=a2 (mod n2)

   .......

    a=ak  (mod nk)

M=n1*n2*n3*....nk

Mi=M/ni

Mi^(-1)是Mi在模ni下的逆元

n1,n2,n3...nk 是质数,a的一个解为 a= a1*M1*M1^(-1)+a2*M2*M2^(-1)+...........+ak*Mk*Mk^(-1)

证明   ai*Mi*Mi^(-1)%ni=ai      j!=i    aj*Mj*Mj^(-1)%ni=0   所以a%ni=ai;



这一题解法:

C(n,m)=ans[1] (mode n1)

C(n,m)=ans[2] (mode n2)

.....

C(n,m)=ans[k] (mode nk)

先用lucas求出ans[1..k],再用中国剩余定理求出C(n,m)

#include<bits/stdc++.h>
using namespace std;
#define rd(x) scanf("%d",&x)
#define rdd(x,y) scanf("%d%d",&x,&y)
#define rddd(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define rds(s) scanf("%s",s)
#define rep(i,n) for(int i=0;i<n;i++)
#define LL long long
const int N = 1e3+10;
const int inf=1e9;
const int MOD=1e9+7;
LL n,m;
int p[15];
int k;
void add(LL &a,LL b,LL md){
  a+=b;
  a%=md;
}
LL mul(LL a,LL b,LL md){
    LL ret=0;
    while(b){
        if(b&1)  add(ret,a,md);
        add(a,a,md);
        b>>=1;
    }
    return ret;
}
LL qmod(LL a,LL b,LL md){
    LL ret=1;
    while(b){
        if(b&1) ret=mul(ret,a,md);
        a=mul(a,a,md);
        b>>=1;
    }
    return ret;
}
LL C(LL n,LL m,LL md){
    LL up=1,down=1;
    rep(i,m){
        down=down*(i+1)%md;
        up=up*(n-i)%md;
    }
    return mul(up,qmod(down,md-2,md),md);
}
LL lucas(LL n,LL m,LL md){
    if(n==0 || m==0) return 1;
    return  mul(C(n%md,m%md,md),lucas(n/md,m/md,md),md);
}
LL M;
LL ans[15];
int main()
{
#ifndef ONLINE_JUDGE
  freopen("aaa","r",stdin);
#endif
    int T;
    rd(T);
    while(T--){
          scanf("%I64d%I64d%d",&n,&m,&k);
          M=1;
          rep(i,k) scanf("%d",p+i+1);
          for(int i=1;i<=k;i++){
              ans[i]=lucas(n,m,p[i]);
              M*=p[i];
          }
          LL ret=0;
          for(int i=1;i<=k;i++){
              LL Mi=M/p[i];
              LL Mni=qmod(Mi,p[i]-2,p[i]);
              ret+=mul(mul(ans[i],Mi,M),Mni,M);
               ret%=M;
          }
          printf("%I64d\n",ret);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值