Description
求
∑i=1n∑j=1nd(ij)
Solution
通过陈老师r老师等式可以的得到该式子就等于
∑i=1n∑j=1n⌊ni⌋⌊nj⌋[(i,j)=1]
一波反演以后就得到
∑d=1nμ(d)(∑i=1⌊nd⌋⌊nid⌋)2
发现后面那个东西的取值只有
O(n√)
种,只需要枚举后面的值,前面的用杜教筛求就好了,时间复杂度为
O(n34)
。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <tr1/unordered_map>
using namespace std;
using namespace tr1;
const int MOD = 1000000007;
const int N = 1000100;
typedef long long ll;
int n, Pcnt, x, ans, res, tmp, pos;
int prime[N], mu[N], vis[N];
unordered_map<int, int> MU;
int Mu(int x) {
if (x < N) return mu[x];
if (MU.count(x)) return MU[x];
int pos, res = 1;
for (int i = 2; i <= x; i = pos + 1) {
pos = x / (x / i);
(res -= (ll)(pos - i + 1) * Mu(x / i) % MOD) % MOD;
}
return MU[x] = res;
}
int F(int x) {
int res = 0, pos;
for (int i = 1; i <= x; i = pos + 1) {
pos = x / (x / i);
(res += (ll)(x / i) * (pos - i + 1) % MOD) %= MOD;
}
return res;
}
int main(void) {
mu[1] = 1; scanf("%d", &n);
for (int i = 2; i < N; i++) {
if (!vis[i]) {
prime[++Pcnt] = i; mu[i] = -1;
}
for (int j = 1; j <= Pcnt && (x = prime[j] * i) < N; j++) {
vis[x] = 1;
if (i % prime[j]) {
mu[x] = -mu[i];
} else {
mu[x] = 0; break;
}
}
}
for (int i = 2; i < N; i++) mu[i] += mu[i - 1];
for (int i = 1; i <= n; i = pos + 1) {
pos = n / (n / i); tmp = F(n / i);
res = (Mu(pos) - Mu(i - 1) + MOD) % MOD;
res = (ll)res * tmp % MOD * tmp % MOD;
ans = (ans + res) % MOD;
}
printf("%d\n" ,ans);
return 0;
}