題意
首先是套路的化式子爲枚舉gcd:
我們設,莫比烏斯反演可得:
又因爲很好算,等於,那麼代入原式:
我們想把那個移出來,因爲這個東西可以整除分塊算,那麼我們改枚舉倍數爲枚舉約數:
我們想起來莫比烏斯函數有一個性質:
兩邊同時乘上,那麼:
我們發現這個式子和答案後面那個式子是一樣的,那麼:
我們用杜教篩算歐拉函數的前綴和整除分塊做就好了,複雜度。
#include <bits/stdc++.h>
#define pb push_back
#define ll long long
#define For(i, a, b) for (int i = a; i <= b; ++ i)
using namespace std;
const int N = 2e6;
const int mod = 1e9 + 7;
vector<int> Prime;
bitset<N + 3> Notp;
unordered_map<ll, int> SPhi;
int Phi[N + 3], Sphi[N + 3];
int Mul(int x, int y) { return 1ll * x * y % mod; }
int Add(int x, int y) { return (x += y) < mod ? x : x - mod; }
void Get_Prime() {
Notp[0] = Notp[1] = Phi[1] = 1;
For(i, 2, N) {
if (!Notp[i]) Prime.pb(i), Phi[i] = i - 1;
for (auto P : Prime) {
if (P * i > N) break;
Notp[P * i] = 1;
if (!(i % P)) {
Phi[P * i] = Mul(Phi[i], P);
break;
}
Phi[P * i] = Mul(Phi[i], P - 1);
}
}
For(i, 1, N) Sphi[i] = Add(Sphi[i - 1], Phi[i]);
}
int Query_Phi(ll n) {
if (n <= N) return Sphi[n];
if (SPhi[n]) return SPhi[n];
int res = ((n % mod) * (n % mod + 1)) % mod * (mod + 1) / 2 % mod;
for (ll l = 2, r; l <= n; l = r + 1) {
r = n / (n / l);
res = Add(res, mod - 1ll * Query_Phi(n / l) * (r - l + 1) % mod);
}
return SPhi[n] = res;
}
int main() {
ll n, ans = 0;
Get_Prime();
cin >> n;
for (ll l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);
ans += 1ll * Mul(n / l % mod, n / l % mod) * (Query_Phi(r) - Query_Phi(l - 1)) % mod;
}
printf("%lld\n", (ans % mod + mod) % mod);
return 0;
}