题目大意:给定正整数 q,n(1≤q,n≤109) q , n ( 1 ≤ q , n ≤ 10 9 ) ,求 q∑d|nCdnmod999911659 q ∑ d | n C n d mod 999911659 。
若
q=999911659
q
=
999911659
,则上试结果为
0
0
。
否则,因为是素数,所以
q,n
q
,
n
互素。由欧拉定理,得:
关键在于计算
∑d|nCdnmod999911658
∑
d
|
n
C
n
d
mod
999911658
的值。
发现模数太大了,不能直接用Lucas定理求解。我们要换一种思路。
分解素因数得: 999911658=2×3×4679×35617 999911658 = 2 × 3 × 4679 × 35617 。我们只要分别计算 ∑d|nCdnmod2,3,4679,35617 ∑ d | n C n d mod 2 , 3 , 4679 , 35617 的值,就可以用中国剩余定理或者exgcd计算出指数,从而用快速幂算出最终的答案。
#include <cstdio>
typedef long long ll;
const ll mod = 999911659;
const ll mo[] = {2, 3, 4679, 35617};
const ll m[] = {mod / 2, mod / 3, mod / 4679, mod / 35617};
const ll maxm = 35627;
ll n, g, cmo, cm, fac[maxm], inv[maxm], res, ans;
ll mpow(ll x, ll y, ll z) {
ll u = 1;
for (; y; y >>= 1) {
if (y & 1) {
u = x * u % z;
}
x = x * x % z;
}
return u;
}
ll calc(ll a, ll b) {
if (b < 0 || b > a) {
return 0;
} else if (b == 0 || b == a) {
return 1;
} else {
return fac[a] * inv[a - b] % cmo * inv[b] % cmo;
}
}
ll lucas(ll a, ll b) {
if (a | b) {
return lucas(a / cmo, b / cmo) * calc(a % cmo, b % cmo) % cmo;
} else {
return 1;
}
}
int main() {
scanf("%lld %lld", &n, &g);
if (g == mod) {
puts("0");
return 0;
}
for (int k = 0; k < 4; k++) {
cmo = mo[k], cm = m[k];
fac[0] = 1, inv[0] = 1;
for (int i = 1; i < cmo; i++) {
fac[i] = fac[i - 1] * i % cmo;
inv[i] = mpow(fac[i], cmo - 2, cmo);
}
res = 0;
for (int i = 1; i * i <= n; i++) {
if (n % i == 0) {
if (i * i == n) {
res = (res + lucas(n, i)) % cmo;
} else {
res = (res + lucas(n, i)) % cmo;
res = (res + lucas(n, n / i)) % cmo;
}
}
}
ll t = mpow(cm, cmo - 2, cmo) * cm % (mod - 1);
ans = (ans + t * res % (mod - 1)) % (mod - 1);
}
printf("%lld\n", mpow(g, ans, mod));
return 0;
}