原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=6390
题意
∑
a
=
1
m
∑
b
=
1
n
G
u
(
a
,
b
)
\sum_{a=1}^{m}\sum_{b=1}^{n}Gu(a,b)
a=1∑mb=1∑nGu(a,b)
G
u
(
a
,
b
)
=
ϕ
(
a
b
)
ϕ
(
a
)
ϕ
(
b
)
Gu(a,b)=\frac{\phi(ab)}{\phi(a)\phi(b)}
Gu(a,b)=ϕ(a)ϕ(b)ϕ(ab)
化简
首 先 考 虑 对 G u 函 数 进 行 变 换 , 利 用 到 欧 拉 函 数 的 性 质 ϕ ( p k ) = ( p − 1 ) p k − 1 ( p 为 质 数 ) 首先考虑对Gu函数进行变换,利用到欧拉函数的性质\phi(p^k)=(p-1)p^{k-1}(p为质数) 首先考虑对Gu函数进行变换,利用到欧拉函数的性质ϕ(pk)=(p−1)pk−1(p为质数)
G u ( a , b ) = ϕ ( p 1 2 k 1 p 2 2 k 2 . . p n 2 k n ) ϕ ( p 1 k 1 p 2 k 2 . . p n k n ) ϕ ( p 1 k 1 p 2 k 2 . . p n k n ) Gu(a,b)=\frac{\phi(p1^{2k1}p2^{2k2}..pn^{2kn})}{\phi(p1^{k1}p2^{k2}..pn^{kn})\phi(p1^{k1}p2^{k2}..pn^{kn})} Gu(a,b)=ϕ(p1k1p2k2..pnkn)ϕ(p1k1p2k2..pnkn)ϕ(p12k1p22k2..pn2kn)
= ( p 1 − 1 ) p 1 2 k 1 − 1 . . ( p n − 1 ) p n 2 k n − 1 ( p 1 − 1 ) 2 p 1 2 k 1 − 2 . . ( p n − 1 ) 2 p n 2 k n − 2 =\frac{(p1-1)p1^{2k1-1}..(pn-1)pn^{2kn-1}}{(p1-1)^2p1^{2k1-2}..(pn-1)^2pn^{2kn-2}} =(p1−1)2p12k1−2..(pn−1)2pn2kn−2(p1−1)p12k1−1..(pn−1)pn2kn−1
= p 1 p 2.. p n ( p 1 − 1 ) ( p 2 − 1 ) . . ( p n − 1 ) =\frac{p1p2..pn}{(p1-1)(p2-1)..(pn-1)} =(p1−1)(p2−1)..(pn−1)p1p2..pn
= p 1 p 2.. p n ϕ ( p 1 p 2.. p n ) =\frac{p1p2..pn}{\phi(p1p2..pn)} =ϕ(p1p2..pn)p1p2..pn
= g c d ( a , b ) ϕ ( g c d ( a , b ) ) =\frac{gcd(a,b)}{\phi(gcd(a,b))} =ϕ(gcd(a,b))gcd(a,b)
接 下 来 就 是 熟 悉 的 模 型 接下来就是熟悉的模型 接下来就是熟悉的模型
∑ a = 1 m ∑ b = 1 n G u ( a , b ) \sum_{a=1}^{m}\sum_{b=1}^{n}Gu(a,b) a=1∑mb=1∑nGu(a,b)
= ∑ a = 1 m ∑ b = 1 n g c d ( a , b ) ϕ ( g c d ( a , b ) ) =\sum_{a=1}^{m}\sum_{b=1}^{n}\frac{gcd(a,b)}{\phi(gcd(a,b))} =a=1∑mb=1∑nϕ(gcd(a,b))gcd(a,b)
设 g c d ( a , b ) = d 设gcd(a,b)=d 设gcd(a,b)=d
= ∑ d = 1 m i n ( n , m ) d ϕ ( d ) ∑ a = 1 m ∑ b = 1 n [ g c d ( a , b ) = d ] =\sum_{d=1}^{min(n,m)}\frac{d}{\phi(d)}\sum_{a=1}^{m}\sum_{b=1}^{n}[gcd(a,b)=d] =d=1∑min(n,m)ϕ(d)da=1∑mb=1∑n[gcd(a,b)=d]
= ∑ d = 1 m i n ( n , m ) d ϕ ( d ) ∑ a = 1 m / d ∑ b = 1 n / d ∑ t ∣ a , t ∣ b μ ( t ) =\sum_{d=1}^{min(n,m)}\frac{d}{\phi(d)}\sum_{a=1}^{m/d}\sum_{b=1}^{n/d}\sum_{t|a,t|b}\mu(t) =d=1∑min(n,m)ϕ(d)da=1∑m/db=1∑n/dt∣a,t∣b∑μ(t)
= ∑ d = 1 m i n ( n , m ) d ϕ ( d ) ∑ t = 1 m i n ( n , m ) / d μ ( t ) ∑ a = 1 m / t d ∑ b = 1 n / t d =\sum_{d=1}^{min(n,m)}\frac{d}{\phi(d)}\sum_{t=1}^{min(n,m)/d}\mu(t)\sum_{a=1}^{m/td}\sum_{b=1}^{n/td} =d=1∑min(n,m)ϕ(d)dt=1∑min(n,m)/dμ(t)a=1∑m/tdb=1∑n/td
= ∑ d = 1 m i n ( n , m ) d ϕ ( d ) ∑ t = 1 m i n ( n , m ) / d μ ( t ) [ m t d ] [ n t d ] =\sum_{d=1}^{min(n,m)}\frac{d}{\phi(d)}\sum_{t=1}^{min(n,m)/d}\mu(t)[\frac{m}{td}][\frac{n}{td}] =d=1∑min(n,m)ϕ(d)dt=1∑min(n,m)/dμ(t)[tdm][tdn]
设 f ( n , m ) = ∑ i = 1 m i n ( n , m ) μ ( t ) [ m i ] [ n i ] 设f(n,m)=\sum_{i=1}^{min(n,m)}\mu(t)[\frac{m}{i}][\frac{n}{i}] 设f(n,m)=i=1∑min(n,m)μ(t)[im][in]
f ( n , m ) 用 整 除 分 块 可 以 在 ( n ) 的 时 间 复 杂 里 完 成 f(n,m)用整除分块可以在\sqrt(n)的时间复杂里完成 f(n,m)用整除分块可以在(n)的时间复杂里完成
原 式 = ∑ d = 1 m i n ( n , m ) d ϕ ( d ) f ( n d , m d ) 原式=\sum_{d=1}^{min(n,m)}\frac{d}{\phi(d)}f(\frac{n}{d},\frac{m}{d}) 原式=d=1∑min(n,m)ϕ(d)df(dn,dm)
因 为 ϕ ( d ) < d , 因 此 用 线 性 求 一 下 逆 元 , 那 么 总 的 时 间 复 杂 度 就 是 O ( n l o g n ) 因为\phi(d)<d,因此用线性求一下逆元,那么总的时间复杂度就是O(nlogn) 因为ϕ(d)<d,因此用线性求一下逆元,那么总的时间复杂度就是O(nlogn)
Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <bitset>
#include <map>
#include <set>
#include <stack>
#include <queue>
//#include <unordered_map>
using namespace std;
#define fi first
#define se second
#define re register
typedef long long ll;
typedef pair<ll, ll> PII;
typedef unsigned long long ull;
const int N = 1e6 + 10, M = 1e6 + 5, INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
ll prime[N], mu[N], k, p;
ll phi[N], inv[N];
bool is_prime[N];
void get_inv(int n) { //线性递推
inv[1] = 1;
for(int i = 2; i < n; i++)
inv[i] = 1ll*(p - p / i) * inv[p % i] % p;
}
inline void init(int n) {
memset(is_prime, true, sizeof is_prime);
mu[1] = 1; phi[1] = 1;
for (int i = 2; i < n; ++i) {
if (is_prime[i]) prime[++k] = i, mu[i] = -1, phi[i] = i-1;
for (int j = 1; j <= k && i * prime[j] < n; ++j) {
is_prime[i * prime[j]] = false;
if (i % prime[j] == 0) {
phi[i * prime[j]] = phi[i] * prime[j];
break;
} else {
mu[i * prime[j]] = -mu[i];
phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
}
for (int i = 1; i < n; ++i) mu[i] += mu[i-1];
}
ll calc(ll n, ll m) {
ll ans = 0;
for (ll l = 1, r; l <= min(n, m); l = r + 1) {
r = min(m / (m / l), n / (n / l));
ans = (ans + (mu[r] - mu[l-1] + p) % p * (n / l) % p * (m / l) % p) % p;
}
return ans;
}
void solve() {
init(N);
int T; cin >> T; while (T--) {
int m, n; cin >> m >> n >> p;
get_inv(min(n, m));
ll ans = 0;
for (int i = 1; i <= min(n, m); i++) ans = (ans + i * inv[phi[i]] % p * calc(n/i, m/i) % p) % p;
cout << ans << endl;
}
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#ifdef ACM_LOCAL
freopen("input", "r", stdin);
freopen("output", "w", stdout);
#endif
solve();
return 0;
}