1. 程式人生 > >HDU5446:Unknown Treasure——題解

HDU5446:Unknown Treasure——題解

+++ ble clu nbsp image .html logs pos typedef

http://acm.hdu.edu.cn/showproblem.php?pid=5446

求C(n,m)%(p1p2…pk)的值,其中pi均為質數。

參考:https://www.cnblogs.com/linyujun/p/5199684.html

預備知識:

1.Lucas定理(圖片來自百科):當p為素數時,有

技術分享圖片

2.中國剩余定理:

技術分享圖片

3.求逆元。

根據中國剩余定理可知,我們求C(n,m)%(p1p2…pk),實際就是在求解同余方程組:

C(n,m)%p1=a1

C(n,m)%p2=a2

……

C(n,m)%p3=a3

最終求得的C(n,m)即是在%(p1p2…pk)意義下的。

根據lucas定理,我們能立刻求出所有a的值。

在那之後用中國剩余定理求解即可。

(另外如果逆元不存在的話我就不知道怎麽做了emmm……不過看數據貌似避開了這個問題)

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long
long ll; ll qpow(ll k,ll n,ll p){ ll ans=1; while(n){ if(n&1)ans=ans*k%p; k=k*k%p;n>>=1; } return ans; } ll mul(ll a,ll b,ll p){ ll ans=0; while(b){ if(b&1)ans=(ans+a)%p; a=(a<<1)%p;b>>=1; } return
ans; } ll C(ll n,ll m,ll p){ if(n<m)return 0; if(n==m)return 1; if(m>n-m)m=n-m; ll cn=1,cm=1; for(ll i=0;i<m;i++){ cn=cn*(n-i)%p; cm=cm*(m-i)%p; } return cn*qpow(cm%p,p-2,p)%p; } ll lucas(ll n,ll m,ll p){ ll ans=1; while(n&&m&&ans){ ans=ans*C(n%p,m%p,p)%p; n/=p;m/=p; } return ans; } int t; ll n,m,k,p[11],r[11],P; int main(){ cin>>t; while(t--){ cin>>n>>m>>k;P=1; for(int i=1;i<=k;i++){ cin>>p[i];P*=p[i]; r[i]=lucas(n,m,p[i]); } ll ans=0; for(int i=1;i<=k;i++){ ll w=P/p[i],inv=qpow(w%p[i],p[i]-2,p[i]); ans=(ans+mul(w*inv,r[i],P))%P; } printf("%lld\n",ans); } return 0; }

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+歡迎訪問我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

HDU5446:Unknown Treasure——題解