已知
n2−3n+2=∑d|nf(d)
求
∑ni=1f(i)
n <= 10^9
莫比乌斯反演得:
f(n)=∑d|ng(d)∗mu(n/d)
∑i=1nf(i)=∑i=1ng(i)∗∑j=1n/imu(j)
考虑求莫比乌斯的前缀和,设M(i)为mu的前缀和,则有:
∑i=1nM(⌊n/i⌋)=1
这样就可以先预处理100W以内的值,然后记忆化搜索来求。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <ctime>
#include <cassert>
#define Rep(i, x, y) for (int i = x; i <= y; i ++)
#define Dwn(i, x, y) for (int i = x; i >= y; i --)
#define RepE(i, x) for(int i = pos[x]; i; i = g[i].nex)
using namespace std;
typedef long long LL;
const int mod = 1000000007, M = 5000005, m2 = 1000007, inf = 1 << 30;
struct Hash {
struct Link { int x, nex, w; } g[M];
int pos[m2], sz;
int Find(int x) { RepE(i, x % m2) if (g[i].x == x) return g[i].w; return inf; }
void Add(int x, int w) { assert(sz < M); g[++ sz] = (Link) { x, pos[x % m2], w }, pos[x % m2] = sz; }
} m1;
int T, n, pri[M], u[M], tot, sum[M]; bool c[M]; LL ans;
void PreWork() {
u[1] = sum[1] = 1;
Rep(i, 2, M - 1) {
if (!c[i]) pri[tot ++] = i, u[i] = -1;
Rep(j, 0, tot - 1) {
int k = i * pri[j];
if (k >= M) break ;
c[k] = 1;
if (i % pri[j] == 0) { u[k] = 0; break ; }
else u[k] = -u[i];
}
sum[i] = sum[i - 1] + u[i];
}
}
LL S(int n) {
LL s1 = 0;
if (n < M) return sum[n];
for (int i = 2, lt; i <= n; i = lt + 1) {
lt = n / (n / i);
if (n / i < M) s1 += (LL)sum[n / i] * (lt - i + 1);
else {
int k = m1.Find(n / i);
if (k == inf) {
m1.Add(n / i, k = S(n / i));
}
s1 += (LL)k * (lt - i + 1);
}
}
return 1 - s1;
}
LL G(LL n) {
if ((2 * n + 1) % 3 == 0) return ((n * (n + 1) / 2) % mod) * ((2 * n + 1) / 3) % mod;
return ((n * (n + 1) / 6) % mod) * (2 * n + 1) % mod;
}
int main()
{
scanf ("%d", &T);
PreWork();
while (T --) {
scanf ("%d", &n);
ans = 0;
LL s0 = 0;
for (int i = 1, lt; i <= n; i = lt + 1) {
lt = n / (n / i);
LL k = S(n / i), z = (G(lt) - 3LL * (lt + 1) * lt / 2 + 2LL * lt) % mod;
(ans += (z - s0 + 3LL * mod) * k) %= mod;
s0 = z;
}
printf("%I64d\n", (ans + mod) % mod);
}
return 0;
}