您的位置:首页 > 其它

HDU 5446 Unknown Treasure(中国剩余定理+卢卡斯定理)——2015 ACM/ICPC Asia Regional Changchun Online

2017-10-10 20:34 567 查看
传送门

On the way to the next secret treasure hiding place, the mathematician discovered a cave unknown to the map. The mathematician entered the cave because it is there. Somewhere deep in the cave, she found a treasure chest with a combination lock and some numbers on it. After quite a research, the mathematician found out that the correct combination to the lock would be obtained by calculating how many ways are there to pick m different apples among n of them and modulo it with M. M is the product of several different primes.
[align=left]Input[/align] On the first line there is an integer T(T≤20) representing the number of test cases.

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}.
[align=left]Output[/align] For each test case output the correct combination on a line.
[align=left]Sample Input[/align]
1
9 5 2
3 5

[align=left]Sample Output[/align]
6


题目大意:

给定一个 n,m(1≤m≤n≤1018) ,求 C(n,m)%M 其中 M=p1∗p2∗...∗pk,其中pi为素数

解题思路:

设有 A=C(n,m),X=A(modM),Y=AM,那么有

A−Y∗M=XA(modpi)−Y∗M(modpi)=X(modpi)A(modpi)≡X(modpi)

所以考虑中国剩余定理求得 X, 其中计算 A(modpi) 的时候用卢卡斯定理计算,最后需要用快速乘法,否则爆long long

代码:

#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
using namespace std;
typedef long long LL;
const int MAXN = 1e5+5;
void Exgcd(LL a, LL b, LL &x, LL &y){
if(b == 0){
x = 1;
y = 0;
return;
}
LL x1, y1;
Exgcd(b, a%b, x1, y1);
x = y1;
y = x1 - (a/b)*y1;
}
LL Pow(LL a, LL b, LL c)
{
LL ans = 1;
while(b){
if(b & 1) ans = (ans*a)%c;
b>>=1;
a = (a*a)%c;
}
return ans;
}
LL Multi(LL a, LL b, LL c){
LL ans = 0;
while(b){
if(b & 1) ans = (ans+a)%c;
b>>=1;
a = (a+a)%c;
}
return ans;
}
int C(int a, int b, int c){
if(b > a) return 0;
int tmp = min(b, a-b);
LL t1 = 1, t2 = 1;
for(int i=1; i<=tmp; i++){
t1 = t1*(a-i+1)%c;
t2 = t2*i%c;
}
LL x, y;
Exgcd(t2, c, x, y);
LL ans = t1*x%c;
ans = (ans%c+c)%c;
return ans;
}
LL Lucas(LL n, LL m, int p){
LL ans = 1;
while(n && m){
ans = ans*C(n%p, m%p, p) % p;
n /= p;
m /= p;
}
return ans;
}
LL p[15], a[15];
LL CRT(int n){
LL M = 1, ans = 0;
for(int i=0; i<n; i++) M *= p[i];
for(int i=0; i<n; i++){
LL _M = M/p[i];
LL x, y;
Exgcd(_M, p[i], x, y);
x = (x%p[i]+p[i])%p[i];
LL tmp = Multi(x, _M, M);
ans = (ans+Multi(tmp, a[i], M))%M;
}
ans = (ans%M+M)%M;
return ans;
}
int main(){
int T; scanf("%d", &T);
while(T--){
LL n, m; scanf("%lld%lld",&n,&m);
int k; scanf("%d",&k);
for(int i=0; i<k; i++) scanf("%lld",&p[i]);
for(int i=0; i<k; i++) a[i] = Lucas(n, m, p[i]);
printf("%lld\n",CRT(k));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐