Unknown Treasure
Time Limit: 1500/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 3056 Accepted Submission(s): 1128
Each test case starts with three integers n,m,k(1≤m≤n≤1018,1≤k≤10) on a line where k is the number of primes. Following on the next line are k different primes p1,...,pk. It is guaranteed that M=p1⋅p2⋅⋅⋅pk≤1018 and pi≤105 for every i∈{1,...,k}.
題意:
問組合數 C(n,m) % M 等於多少
其中 n m M 都是 小於等於 10^18 次方的比較大的數字
並且題目給出 M 的唯一分解的所有質因子 p ,求解決上述問題
題解:
首先介紹中國剩餘定理:
逆元詳解:
本題中求逆元 inv數組 還利用了費馬小定理,得到了一個遞推性質,然後快速的求了出來
lucas定理:
C(n , m)= C(n%mod , m%mod)* lucas( n/mod , m/mod )
爆longlong的乘法取模處理:
LL mul(LL a,LL b,LL mod){///二進制,按位相乘
a=(a%mod+mod)%mod;
b=(b%mod+mod)%mod;
LL ans=0;
while(b){
if(b&1) ans+=a,ans=(ans>=mod?ans-mod:ans);
b>>=1; a<<=1;
a=(a>=mod?a-mod:a);
}
return ans;
}
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define maxn 100005
#define LL long long
LL fac[maxn],inv[maxn];
LL powmod(LL a,LL b,LL mod){
LL ans=1;
while(b){
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
void init(int n){
fac[0]=1;
for(int i=1;i<n;i++) fac[i]=fac[i-1]*i%n;
inv[n-1]=powmod(fac[n-1],n-2,n);
for(int i=n-2;i>=0;i--) inv[i]=inv[i+1]*(i+1)%n;
}
LL lucas(LL n,LL m,LL mod){
LL ans=1;
while(n&&m){
LL a=n%mod,b=m%mod;
if(a<b) return 0;
ans=ans*fac[a]%mod*inv[b]%mod*inv[a-b]%mod;
n/=mod,m/=mod;
}
return ans;
}
void ex_gcd(LL a,LL b,LL gcd,LL& x,LL& y){
if(!b) x=1,y=0,gcd=a;
else ex_gcd(b,a%b,gcd,y,x),y-=x*(a/b);
}
LL mul(LL a,LL b,LL mod){
a=(a%mod+mod)%mod;
b=(b%mod+mod)%mod;
LL ans=0;
while(b){
if(b&1) ans+=a,ans=(ans>=mod?ans-mod:ans);
b>>=1; a<<=1;
a=(a>=mod?a-mod:a);
}
return ans;
}
LL china(LL n,LL* a,LL* m){
LL M=1,w,gcd,x,y,ans=0;
for(int i=0;i<n;i++) M*=m[i];
for(int i=0;i<n;i++){
w=M/m[i];
ex_gcd(m[i],w,gcd,x,y);
ans=(ans+mul(mul(y,w,M),a[i],M)+M)%M;
}
return ans;
}
int main()
{
LL k,n,m,a[20],p[20],T;
//freopen("in.txt","r",stdin);
scanf("%lld",&T);
while(T--)
{
scanf("%lld%lld%lld",&n,&m,&k);
for(int i=0;i<k;i++){
scanf("%lld",&p[i]);
init(p[i]);
a[i]=lucas(n,m,p[i]);
}
printf("%lld\n",china(k,a,p));
}
return 0;
}