题意
求 $\sum_{i=1}^n \sum_{j=1}^n gcd(i,j)$.
分析
$$\begin{aligned}
\sum_{i=1}^n \sum_{j=1}^n gcd(i,j) &= \sum_{i=1}^n \sum_{j=1}^n d[gcd(i, j)=d] \\
&= \sum_{d=1}^n d \sum_{i=1}^n \sum_{j=1}^n[gcd(i,j=d)] \\
&= \sum_{d=1}^n d \sum_{i=1}^{\left \lfloor \frac{n}{d} \right \rfloor}\mu (i) \left \lfloor \frac{n}{id} \right \rfloor\left \lfloor \frac{n}{id} \right \rfloor \\
&= \sum_{T=1}^n ({\frac{n}{T}})^2 \sum_{d|T}d\mu (\frac{T}{d}) \\
&= \sum_{T=1}^n ({\frac{n}{T}})^2 \varphi (T)
\end{aligned}$$
使用了几个套路,
一是 $gcd(i,j)=d$ 的经典求和式子;
二是出现 $\sum_{d=1}^n d \sum_{i=1}^{\left \lfloor \frac{n}{d} \right \rfloor}$,枚举 $T=id$;
三是使用结论 $\mu * ID = \varphi$.
求欧拉函数的前缀和可以使用杜教筛。
#include<bits/stdc++.h> using namespace std; const int maxn = 2000010; typedef long long ll; const ll mod = 1000000007; const ll inv2 = (mod+1)>>1; ll T, n, pri[maxn], tot, phi[maxn], sum_phi[maxn]; bool vis[maxn]; unordered_map<ll, ll> mp_phi; //可换成unordered_map ll S_phi(ll x) { if (x < maxn) return sum_phi[x]; if (mp_phi[x]) return mp_phi[x]; ll ret = (x%mod) * ((x+1)%mod) % mod * inv2 % mod; for (ll i = 2, j; i <= x; i = j + 1) { j = x / (x / i); ret =(ret - S_phi(x / i) * (j - i + 1) % mod + mod) % mod; } return mp_phi[x] = ret; } void initPhi() { phi[1] = 1; for (int i = 2; i < maxn; i++) { if (!vis[i]) pri[++tot] = i, phi[i] = i-1; for (int j = 1; j <= tot && i * pri[j] < maxn; j++) { vis[i * pri[j]] = true; if (i % pri[j] == 0) { phi[i * pri[j]] = phi[i] * pri[j] % mod; break; } else { phi[i * pri[j]] = phi[i] * phi[pri[j]] % mod; } } } for (int i = 1; i < maxn; i++) sum_phi[i] = (sum_phi[i - 1] + phi[i]) % mod; } void solve() { ll res = 0; for(ll i = 1, j;i <= n;i = j+1) { j = n / (n / i); ll tmp = (n/i) % mod; res = (res + tmp * tmp % mod * (S_phi(j)-S_phi(i-1) + mod) % mod) % mod; } printf("%lld\n", res); } int main() { initPhi(); scanf("%lld", &n); solve(); return 0; }
参考链接:
1. http://www.ishenping.com/ArtInfo/1581096.html
2. https://oi-wiki.org/math/du/
原文地址:https://www.cnblogs.com/lfri/p/11701280.html