Unknown Treasure
Time Limit: 1500/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 3603 Accepted Submission(s): 1281
Problem Description
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.
Input
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}.
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}.
Output
For each test case output the correct combination on a line.
Sample Input
1 9 5 2 3 5
Sample Output
6
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<algorithm>
#include<queue>
#include<map>
typedef long long LL;
using namespace std;
LL t, n, m,k, p[20], r[20];
LL mul(LL a, LL b, LL p) {//快速乘,计算a*b%p
LL ret = 0;
while (b) {
if (b & 1) ret = (ret + a) % p;
a = (a + a) % p;
b >>= 1;
}
return ret;
}
LL fact(int n, LL p) {//n的阶乘求余p
LL ret = 1;
for (int i = 1; i <= n; i++) ret = ret * i % p;
return ret;
}
void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d) {
if (!b) { d = a, x = 1, y = 0; }
else {
ex_gcd(b, a % b, y, x, d);
y -= x * (a / b);
}
}
LL inv(LL t, LL p) {//如果不存在,返回-1
LL d, x, y;
ex_gcd(t, p, x, y, d);
return d == 1 ? (x % p + p) % p : -1;
}
LL comb(int n, int m, LL p) {//C(n, m) % p
if (m < 0 || m > n) return 0;
return fact(n, p) * inv(fact(m, p), p) % p * inv(fact(n - m, p), p) % p;
}
LL Lucas(LL n, LL m, int p) {
return m ? Lucas(n / p, m / p, p) * comb(n%p, m%p, p) % p : 1;
}
LL china(int n, LL *a, LL *m) {//中国剩余定理
LL M = 1, ret = 0;
for (int i = 0; i < n; i++) M *= m[i];
for (int i = 0; i < n; i++) {
LL w = M / m[i];
//ret = (ret + w * inv(w, m[i]) * a[i]) % M;//这句写了会WA,用下面那句
ret = (ret + mul(w * inv(w, m[i]), a[i], M)) % M;
//因为这里直接乘会爆long long ,所以我用快速乘(unsigned long long也是爆掉,除非用高精度)
}
return (ret + M) % M;
}
int main()
{
cin >> t;
while (t--)
{
scanf("%lld%lld%lld", &n, &m, &k);
for (int i = 0; i < k; i++)
{
scanf("%lld", &p[i]);
}
for (int i = 0; i < k; i++)
r[i] = Lucas(n, m, p[i]);
printf("%lld\n", china(k, r, p));
}
return 0;
}