题意 : 求 \(\sum_{i=1}^{N}{\sum_{j=1}^{M}{\phi(ij)}}; N,M \leq 10^5, q \leq 10^4\)
设 \(N \leq M\).
根据\(\phi\)的性质 可以得到\(\phi(ij)=\frac{\phi(i)\phi(j)gcd(i,j)}{\phi(gcd(i,j))}\)
如果这一步没想到,只能说是莫反做的不够多了...
\(nm\)过大的情况下是没法处理乘积的,而且直接这么看也看不出什么性质来
所以考虑把乘在一起的\(ij\)分开处理。
于是 \(\sum_{i=1}^{N}{\sum_{j=1}^{M}{\phi(ij)}} = \sum_{i=1}^{N}{\sum_{j=1}^{M}{\frac{\phi(i)\phi(j)gcd(i,j)}{\phi(gcd(i,j))}}}\),
将\(gcd(i,j)\)相关提出来 可以得到
\(\sum_{i=1}^{N}{\sum_{j=1}^{M}{\frac{\phi(i)\phi(j)gcd(i,j)}{\phi(gcd(i,j))}}}=\sum_{d=1}^{N}{\frac{d}{\phi(d)}\sum_{i=1}^{N/d}{\sum_{j=1}^{M/d}{\phi(id)\phi(jd)}{\sum_{e|gcd(i,j)}{\mu(e)}}}}\)
常规性地开始枚举\(e\) 得到 \(\sum_{d=1}^{N}{\frac{d}{\phi(d)}\sum_{e=1}^{N/d}{\mu(e){\sum_{i=1}^{N/de}{\sum_{j=1}^{M/de}{\phi(ide)\phi(jde)}}}}}\)
习惯性地枚举\(de\) 得到 \(\sum_{T=1}^{N}{\sum_{i=1}^{N/T}{\phi(iT)\sum_{j=1}^{M/T}{\phi(jT)}}\sum_{d|T}{\phi(\frac{T}{d})\frac{d}{\phi(d)}}}\)
设\(f(T)=\sum_{d|T}{\phi(\frac{T}{d})\frac{d}{\phi(d)}}\) , \(G(N,T)=\sum_{i=1}^{N}{\phi(iT)}\), 代入上式得 :
\(\sum_{T=1}^{N}{\sum_{i=1}^{N/T}{\phi(iT)\sum_{j=1}^{M/T}{\phi(jT)}}\sum_{d|T}{\phi(\frac{T}{d})\frac{d}{\phi(d)}}}=\sum_{T=1}^{N}{G(N/T,T)G(M/T,T)f(T)}\)
设 \(S(n,i,j)=\sum_{T=1}^{n}G(iT,T)G(jT,T)f(T)\)
那么设\(\lfloor{N/T}\rfloor==i,\lfloor{M/T}\rfloor==j\)时\(N\)的最大值为\(up\),最小值为\(down\) 那么
此时的\(ans=S(up,i,j) - S(down-1,i,j)\)
因为上界是\(\lfloor{N/T}\rfloor\)所以\(G\)可以用\(NlnN\)内全部暴力预处理出来
\(G(N,T)=G(N-1,T)+\phi(NT)\)
可以预处理一部分\(S\), 其中\(S(N,i,j)=S(N-1,i,j)+G(iN,N)G(jN,N)f(N)\)
经过计算(调参)可以得到上界\(B\)
upd :为啥代码丢到LOJ上就挂的只剩下50了 , 求助。
#include<cstdio>
#include<cstring>
#include<vector>
const int N = 1e5 + 7;
const int lim = 1e5;
const int B = 35;
typedef long long ll;
const int p = 998244353;
inline int max (int a, int b) {
return a > b ? a : b;
}
inline int min (int a, int b) {
return a > b ? b : a;
}
int isp[N], mu[N], phi[N], prime[N], pcnt;
int *G[N], *S[B + 1][B + 1], f[N], inv[N];
inline void init () {
inv[1] = 1, mu[1] = 1, phi[1] = 1;
for (int i = 2; i <= lim; i++) inv[i] = p - (ll)(p / i) * inv[p % i] % p;
for (int i = 2; i <= lim; i++) {
if (!isp[i]) phi[i] = i - 1, mu[i] = -1, prime[++pcnt] = i;
for (int j = 1; j <= pcnt && prime[j] * i <= lim; j++) {
isp[i * prime[j]] = 1;
if (i % prime[j] == 0) {
phi[i * prime[j]] = phi[i] * prime[j] % p, mu[i * prime[j]] = 0;
break;
}
phi[i * prime[j]] = phi[i] * (prime[j] - 1) % p , mu[i * prime[j]] = -mu[i];
}
}
for (int i = 1; i <= lim; i++) for (int j = 1; i * j <= lim; j++) {
f[i * j] = (f[i * j] + (ll) ((ll)i * inv[phi[i]] % p) % p * mu[j] % p) % p;
}
for (int i = 1; i <= lim; i++) {
int upmax = lim / i;
G[i] = new int [upmax + 1];
G[i][0] = 0;
for (int j = 1; j <= upmax; j++) G[i][j] = (ll)((ll)G[i][j - 1] + (ll)phi[i * j]) % p;
}
for (int j = 1; j <= B; j++) for (int k = 1; k <= B; k++) {
int upmax = (lim / max (j, k));
S[j][k] = new int [upmax + 1];
S[j][k][0] = 0;
for (int i = 1; i <= upmax; i++) {
S[j][k][i] = (ll)((ll)S[j][k][i - 1] + ll((ll)f[i] * G[i][j] % p * G[i][k])) % p;
}
}
}
int main () {
int T;
scanf ("%d", &T);
init ();
while (T--) {
int n, m, tmp;
scanf ("%d%d", &n, &m);
if (n > m) tmp = n, n = m, m = tmp;
ll ans = 0;
for (int i = 1, upmax = m / B; i <= upmax; i++)
ans = (ans + ((ll)f[i] * G[i][n / i] % p * G[i][m / i] % p)) % p;
for (int l = m / B + 1, r; l <= n; l = r + 1) {
r = min (n / (n / l), m / (m / l));
ans = (ans + (ll(S[n / l][m / l][r] - S[n / l][m / l][l - 1]) % p + p) % p) % p;
}
printf ("%lld\n", ans);
}
return 0;
}