链接:
hdu 5446
http://acm.hdu.edu.cn/showproblem.php?pid=5446
题意:
给你三个数$n, m, k$
第二行是$k$个数,$p_1,p_2,p_3 cdots p_k$
所有$p$的值不相同且p都是质数
求$C(n, m) \% (p_1*p_2*p_3* cdots *p_k)$的值
范围:$1leq mleq nleq 1e18, 1leq kleq 10,p_ileq 1e5$,保证$p_1*p_2*p_3* cdots *p_k leq 1e18$
分析:
我们知道题目要求$C(n, m) \% (p_1*p_2*p_3* cdots *p_k)$的值
其实这个就是中国剩余定理最后算出结果后的最后一步求余
那$C(n, m)$相当于以前我们需要用中国剩余定理求的值
然而$C(n, m)$太大,我们只好先算出$C(n,m) \% p_1 = r_1 \ C(n,m) \% p_2 = r_2 \ C(n,m) \% ; p_3 = r_3 \ vdots \ C(n,m) \% p_k = r_k \$
用$Lucas$,这些$r_1,r_2,r_3 cdots r_k$可以算出来,然后又是用中国剩余定理求答案。
注意,有些地方直接乘会爆long long,按位乘可避免。
AC代码:
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> using namespace std;; typedef long long LL; void gcd(LL a, LL b, LL &d, LL &x, LL &y) { if (!b) { d = a; x = 1; y = 0; } else { gcd(b, a % b, d, y, x); y -= x * (a / b); } } LL quickmul(LL m, LL n, LL k) { m = (m % k + k) % k; n = (n % k + k) % k; //变成较小的正数 LL res = 0; while (n > 0) { if (n & 1) res = (res + m) % k; m = (m + m) % k; n = n >> 1; } return res; } //计算模n下a的逆。如果不存在逆,返回-1 //ax=1(mod n) LL inv(LL a, LL n) { LL d, x, y; gcd(a, n, d, x, y); return d == 1 ? (x + n) % n : -1; } //n! % p LL fact(LL n, LL p) { LL ret = 1; for (int i = 1; i <= n; i++) ret = ret * i % p; return ret; } LL comp(LL n, LL m, LL p) { if (n < 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 a, LL b, LL m) { LL ans = 1; while (a && b) { ans = quickmul(ans, comp(a % m, b % m, m), m) % m; a /= m; b /= m; } return ans; } //n个方程:x=a[i](mod m[i]) LL china(int n, LL* a, LL* m) { LL M = 1, d, y, x = 0; for (int i = 0; i < n; i++) M *= m[i]; for (int i = 0; i < n; i++) { LL w = M / m[i]; gcd(m[i], w, d, d, y); x = (x + quickmul(quickmul(w,y, M),a[i],M)) % M; //直接乘会爆long long,要用按位乘 } return (x + M) % M; } int k; LL n, m; LL p[10 + 5],r[10 + 5]; int main() { int T; scanf("%d", &T); while (T--) { cin >> n >> m >> k; for (int i = 0; i < k; i++) cin >> p[i]; for (int i = 0; i < k; i++) r[i] = lucas(n, m, p[i]); LL ans = china(k, r, p); cout << ans << endl; } return 0; }