题解 毒瘤之神的考验
题目大意
有\(T\)组查询,每次查询给出\(n,m\),求出:
\[\sum_{i=1}^{n} \sum_{j=1}^{m} \varphi(ij) \bmod 998244353
\]
\(T\le 10^4,n,m\le 10^5\)
思路
首先,你需要知道一个东西:
\[\varphi(ij)=\dfrac{\varphi(i)\varphi(j)\gcd(i,j)}{\varphi(\gcd(i,j))}
\]
证明的话直接展开即可。
于是,我们就可以推得答案即为:
\[\sum_{k=1}^{\min(n,m)}(\sum_{d|k} \dfrac{d}{\varphi(d)}\mu(\dfrac{k}{d}))(\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor} \varphi(ik))(\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}\varphi(jk))
\]
我们发现前面那个东西我们可以\(\Theta(n\log n)\)预处理出来,我们设为\(F(k)\),那么\(F(k)=\sum_{d|k} \dfrac{d}{\varphi(d)}\mu(\frac{k}{d})\),所以式子就是:
\[\sum_{k=1}^{\min(n,m)} F(k) (\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor} \varphi(ik))(\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}\varphi(jk))
\]
我们发现如果我们设\(G(y,x)=\sum_{i=1}^{x} \varphi(iy)\),那么答案即为:
\[\sum_{k=1}^{\min(n,m)}F(k) G(k,\lfloor\frac{n}{k}\rfloor)G(k,\lfloor\frac{m}{k}\rfloor)
\]
所以,如果我们设答案\(S(y,z,x)=\sum_{k=1}^{x} F(k)(\sum_{i=1}^{y} \varphi(ik))(\sum_{j=1}^{z} \varphi(jk))\)
那么可以得到:
\[S(y,z,x)=S(y,z,x-1)+F(x)G(x,y)G(x,z)
\]
然后我们结合一下式子,就可以发现答案是可以整除分块的。但是直接这样搞的话预处理是\(\Theta(n^2)\)的,于是我们可以设一个阈值,然后卡一下就可以过了。
\(\texttt{Code}\)
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define mod 998244353
#define MAXN 100005
#define B 35
int *G[MAXN],*S[B + 5][B + 5];
int T,cnt,F[MAXN],mu[MAXN],inv[MAXN],phi[MAXN],vis[MAXN],prime[MAXN];
int mul (int a,int b){return 1ll * a * b % mod;}
int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
void Euler (int up){
mu[1] = phi[1] = inv[1] = 1;
for (Int i = 2;i <= up;++ i){
if (!vis[i]) prime[++ cnt] = i,phi[i] = i - 1,mu[i] = -1;
for (Int j = 1;j <= cnt && i * prime[j] <= up;++ j){
vis[i * prime[j]] = 1;
if (i % prime[j] == 0){
phi[i * prime[j]] = phi[i] * prime[j];
mu[i * prime[j]] = 0;
break;
}
else mu[i * prime[j]] = -mu[i],phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
for (Int i = 2;i <= up;++ i) inv[i] = mod - 1ll * (mod / i) * inv[mod % i] % mod;
for (Int i = 1;i <= up;++ i) mu[i] = mu[i] < 0 ? mod + mu[i] : mu[i];
for (Int i = 1;i <= up;++ i)
for (Int j = 1;i * j <= up;++ j)
F[i * j] = add (F[i * j],mul (mul (i,inv[phi[i]]),mu[j]));
for (Int i = 1;i <= up;++ i){
G[i] = new int [up / i + 1];G[i][0] = 0;
for (Int j = 1;j <= up / i;++ j)
G[i][j] = add (G[i][j - 1],phi[i * j]);
}
for (Int j = 1;j <= B;++ j)
for (Int k = 1;k <= B;++ k){
int len = up / max (j,k);
S[j][k] = new int [len + 1];S[j][k][0] = 0;
for (Int i = 1;i <= len;++ i)
S[j][k][i] = add (S[j][k][i - 1],mul (F[i],mul (G[i][j],G[i][k])));
}
}
int Solve (int n,int m){
if (n > m) swap (n,m);int sum = 0;
for (Int i = 1;i <= m / B;++ i) sum = add (sum,mul (F[i],mul (G[i][n / i],G[i][m / i])));
for (Int l = m / B + 1,r;l <= n;l = r + 1){
r = min (n / (n / l),m / (m / l));
sum = add (sum,dec (S[n / l][m / l][r],S[n / l][m / l][l - 1]));
}
return sum;
}
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
signed main(){
read (T),Euler (1e5);
while (T --){
int n,m;read (n,m);
write (Solve (n,m)),putchar ('\n');
}
return 0;
}