杜教筛+莫比乌斯反演

· · 题解

题目传送门

题目大意:

T 组数据,每组数据给出一个 n,求:

\sum_{i=1}^{n}{\sum_{j=i+1}^{n}{\gcd(i,j)}}

2^{64} 取模!

前置芝士:

1.杜教筛(先在这里留个坑,以后再填)

2.莫比乌斯反演(可以看看这个莫比乌斯反演)

先颓一下式子:

\sum_{i=1}^{n}{\sum_{j=i+1}^{n}{\gcd(i,j)}} =\sum_{i=1}^{n}{\sum_{j=1}^{i-1}{\gcd(i,j)}}

设 d 为 \gcd(i,j)

d \sum_{i=1}^{n}{ \sum_{j=1}^{i-1}{ \left [ \gcd(i,j)=d\right ]} } }

同时除以 d

d \sum_{i=1}^{\left \lfloor \frac{n}{d} \right \rfloor}{ \sum_{j=1}^{i-1}{ \left [ \gcd(i,j)=1\right ]} } }

因为:

\sum_{i=1}^{n-1}{\left [ \gcd(i,n)=1 \right ]}=\varphi(n)

所以:

\sum_{d=1}^{n}{ d \sum_{i=1}^{\left \lfloor \frac{n}{d} \right \rfloor}{ \sum_{j=1}^{i-1}{ \left [ \gcd(i,j)=1\right ]} } } d \sum_{i=1}^{\left \lfloor \frac{n}{d} \right \rfloor}{ \varphi(i) } } 对于取模,开 unsigned long long 即可自动溢出取模。 代码: ```cpp #include <bits/stdc++.h> #define int unsigned long long #define N 10000000 using namespace std; template <typename T> inline int read() { T n = 0, m = 1; char c = getchar(); while (!isdigit(c)) { if (c == '-') m = -1; c = getchar(); } while (isdigit(c)) { n = (n << 1) + (n << 3) + c - '0'; c = getchar(); } return n * m; } template <typename T> inline void write(T n) { if (n > 9) write(n / 10); putchar((n % 10) + '0'); } unordered_map <int, int> mp; int tot, prime[10000001], phi[10000001]; bool v[10000001]; void get() { phi[1] = 1; for (int i = 2; i <= N; i++) { if (!v[i]) prime[++tot] = i, phi[i] = i - 1; for (int j = 1; j <= tot && prime[j]*i <= N; j++) { v[prime[j]*i] = 1; if (!(i % prime[j])) { phi[i * prime[j]] = phi[i] * prime[j]; break; } phi[i * prime[j]] = phi[i] * (prime[j] - 1); } } for (int i = 1; i <= N; i++) phi[i] += phi[i - 1]; } int sum(int n) { return ((n & 1) ? (n + 1) / 2 * n : n / 2 * (n + 1)); } int get_phi(int n) { if (n <= N) return phi[n]; if (mp[n]) return mp[n]; int ans = sum(n); for (int l = 2, r; l <= n; l = r + 1) { r = n / (n / l); ans -= (r - l + 1) * get_phi(n / l); } mp[n] = ans; return ans; } int ans(int n) { int ans = 0; for (int l = 1, r; l <= n; l = r + 1) { r = n / (n / l); ans += (get_phi(n / l) - 1) * (sum(r) - sum(l - 1)); } return ans; } signed main() { get(); int t = read<int>(); while (t--) write<int>(ans(read<int>())), puts(""); return 0; } ```