题目大意:给定正整数 ,求 。
若
,则上试结果为
。
否则,因为
是素数,所以
互素。由欧拉定理,得:
关键在于计算
的值。
发现模数太大了,不能直接用Lucas定理求解。我们要换一种思路。
分解素因数得: 。我们只要分别计算 的值,就可以用中国剩余定理或者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;
}