传送门
我们先将公式进行化简:
∏ i = 1 n ∏ i = 1 n ∏ i = 1 n m g c d ( i , j ) [ k ∣ g c d ( i , j ) ] = m ∑ i = 1 n ∑ j = 1 n ∑ k = 1 n g c d ( i , j ) [ k ∣ g c d ( i , j ) ] \begin{aligned} &\prod_{i=1}^{n}\prod_{i=1}^{n}\prod_{i=1}^{n}m^{gcd(i,j)[k|gcd(i,j)]}&\\ =&m^{\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{k=1}^{n}gcd(i,j)[k|gcd(i,j)]}& \end{aligned} =i=1∏ni=1∏ni=1∏nmgcd(i,j)[k∣gcd(i,j)]mi=1∑nj=1∑nk=1∑ngcd(i,j)[k∣gcd(i,j)]
现在我们单独考虑指数部分:
∑ i = 1 n ∑ j = 1 n ∑ k = 1 n g c d ( i , j ) [ k ∣ g c d ( i , j ) ] = ∑ d = 1 n d f ( d ) ∑ i = 1 n ∑ k = 1 n [ g c d ( i , j ) = d ] = ∑ d = 1 n d f ( d ) ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ [ g c d ( i , j ) = 1 ] = ∑ d = 1 n d f ( d ) ( 2 ∑ i = 1 ⌊ n d ⌋ ϕ ( i ) − 1 ) = 2 ∑ d = 1 n d f ( d ) ∑ i = 1 ⌊ n d ⌋ ϕ ( i ) − ∑ d = 1 n d f ( d ) , 其中 f ( d ) 为 d 的 因 子 个 数 \begin{aligned} &\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{k=1}^{n}gcd(i,j)[k|gcd(i,j)]&\\ =&\sum\limits_{d=1}^{n}df(d)\sum\limits_{i=1}^{n}\sum\limits_{k=1}^{n}[gcd(i,j)=d]&\\ =&\sum\limits_{d=1}^{n}df(d)\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{n}{d}\rfloor}[gcd(i,j)=1]&\\ =&\sum\limits_{d=1}^{n}df(d)(2\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\phi(i)-1)&\\ =&2\sum\limits_{d=1}^{n}df(d)\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\phi(i)-\sum\limits_{d=1}^{n}df(d),\text{其中}f(d)\text{为}d\text{}的因子个数& \end{aligned} ====i=1∑nj=1∑nk=1∑ngcd(i,j)[k∣gcd(i,j)]d=1∑ndf(d)i=1∑nk=1∑n[gcd(i,j)=d]d=1∑ndf(d)i=1∑⌊dn⌋j=1∑⌊dn⌋[gcd(i,j)=1]d=1∑ndf(d)(2i=1∑⌊dn⌋ϕ(i)−1)2d=1∑ndf(d)i=1∑⌊dn⌋ϕ(i)−d=1∑ndf(d),其中f(d)为d的因子个数
对于 ∑ d = 1 n d f ( d ) \sum\limits_{d=1}^{n}df(d) d=1∑ndf(d)我们发现可以进行如下化简求解:
∑ i = 1 n i f ( i ) = ∑ i = 1 n i ∑ j ∣ i 1 = ∑ j = 1 n ∑ j ∣ i i = ∑ j = 1 n j × ( 1 + ⌊ n j ⌋ ) ⌊ n j ⌋ 2 \begin{aligned} &\sum\limits_{i=1}^{n}if(i)&\\ =&\sum\limits_{i=1}^{n}i\sum\limits_{j|i}1&\\ =&\sum\limits_{j=1}^{n}\sum_{j|i}i&\\ =&\sum\limits_{j=1}^{n}\frac{j\times(1+\lfloor\frac{n}{j}\rfloor)\lfloor\frac{n}{j}\rfloor}{2}&\\ \end{aligned} ===i=1∑nif(i)i=1∑nij∣i∑1j=1∑nj∣i∑ij=1∑n2j×(1+⌊jn⌋)⌊jn⌋
对于 ∑ d = 1 n d f ( d ) \sum\limits_{d=1}^{n}df(d) d=1∑ndf(d)我们可以直接通过数论分块来求,对于 ∑ d = 1 n d f ( d ) ∑ i = 1 ⌊ n d ⌋ ϕ ( i ) \sum\limits_{d=1}^{n}df(d)\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\phi(i) d=1∑ndf(d)i=1∑⌊dn⌋ϕ(i)我们可以对 ∑ i = 1 ⌊ n d ⌋ ϕ ( i ) \sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\phi(i) i=1∑⌊dn⌋ϕ(i)进行数论分块用杜教筛求出来,然后在同一块中对 ∑ d = 1 n d f ( d ) \sum\limits_{d=1}^{n}df(d) d=1∑ndf(d)进行数论分块求出来。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
typedef pair<LL, LL> pLL;
typedef pair<LL, int> pLi;
typedef pair<int, LL> pil;;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) x&(-x)
#define name2str(name) (#name)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<
#define FIN freopen("D://code//in.txt","r",stdin)
#define IO ios::sync_with_stdio(false),cin.tie(0)
const double eps = 1e-8;
const int mod = 1000000007;
const int maxn = 5e6 + 3;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;
bool v[maxn];
int n, m, p, cnt, MOD;
int isp[maxn/10], phi[maxn];
int sum[maxn], ssum[maxn];
unordered_map<int, int> dp1, dp2;
int add(int x, int y) {
if(y < 0) x += y;
else x = x - MOD + y;
if(x < 0) x += MOD;
return x;
}
void init() {
phi[1] = ssum[1] = 1;
for(int i = 2; i < maxn; ++i) {
if(!v[i]) {
ssum[i] = 2;
phi[i] = i - 1;
isp[cnt++] = i;
}
for(int j = 0; j < cnt && i * isp[j] < maxn; ++j) {
v[i*isp[j]] = 1;
if(i % isp[j] == 0) {
phi[i*isp[j]] = phi[i] * isp[j];
int pp = 1, x = i;
while(x % isp[j] == 0) x /= isp[j], pp++;
ssum[i*isp[j]] = ssum[i] / pp * (pp + 1);
break;
}
phi[i*isp[j]] = phi[i] * (isp[j] - 1);
ssum[i*isp[j]] = ssum[i] * 2;
}
}
for(int i = 1; i < maxn; ++i) {
sum[i] = add(sum[i-1], phi[i]);
ssum[i] = add(1LL * ssum[i] * i % MOD, ssum[i-1]);
}
}
int getphi(int x) {
if(x < maxn) return sum[x];
if(dp1[x]) return dp1[x];
int ans = (1LL * x * (x + 1) / 2) % MOD;
for(int l = 2, r; l <= x; l = r + 1) {
r = x / (x / l);
int tmp = 1LL * (r - l + 1) * getphi(x/l) % MOD;
ans = add(ans, -tmp);
}
return dp1[x] = ans;
}
int qpow(int x, int n) {
int res = 1;
while(n) {
if(n & 1) res = 1LL * res * x % p;
x = 1LL * x * x % p;
n >>= 1;
}
return res;
}
int getnum(int x) {
if(x < maxn) return ssum[x];
if(dp2[x]) return dp2[x];
int ans = 0;
for(int l = 1, r; l <= x; l = r + 1) {
r = x / (x / l);
LL tmp1 = 1LL * ((x / l) + 1) * (x / l);
LL tmp2 = 1LL * (l + r) * (r - l + 1) / 2;
ans = add(ans, tmp1 * tmp2 / 2 % MOD);
}
return dp2[x] = ans;
}
int main(){
scanf("%d%d%d", &n, &m, &p);
MOD = p - 1;
init();
int ans2 = getnum(n);
int ans1 = 0;
for(int l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);
int tmp1 = getphi(n / l);
int tmp2 = add(getnum(r), -getnum(l-1));
ans1 = add(ans1, 1LL * tmp1 * tmp2 % MOD);
}
ans1 = 2LL * ans1 % MOD;
int ans = add(ans1, -ans2);
printf("%d\n", qpow(m, ans));
return 0;
}