题意:
Your should calculate the total damage to the battlefield. Formally, you should compute
where [(i,j)=1] evaluates to be 1 if gcd(i,j)=1 , otherwise 0 .
f(n)=∑i=1n∑j=1i⌈ij⌉[(i,j)=1],
where [(i,j)=1] evaluates to be 1 if gcd(i,j)=1 , otherwise 0 .
先将艾弗森约定用莫比乌斯函数展开,如 [1] http://blog.youkuaiyun.com/wubaizhe/article/details/77338332 ——WuBaizhe
观察发现,需进行一些预处理,如 [2] http://blog.youkuaiyun.com/qq_30927651/article/details/77341086 ——风所在的街道
细节要点:
1. 对 [w - j + 1, w] 一整段增加 k 时,不需要一个个进行操作,而是可以 g[w - j + 1] += k, g[w + 1] -= k, 这样求一下前缀和,效果就相当于对一整段进行了操作。
2. 预处理出前缀和 sum 之后,可以运用 分块 的想法求和,[i, n / (n / i)] 的这段区间内 n / i 的值相同
Code:
#include <bits/stdc++.h>
#define maxn 1000000
typedef long long LL;
const LL mod = 1e9 + 7;
bool check[maxn + 10];
int mu[maxn + 10], prime[maxn + 10], n, maxq;
LL g[maxn + 10], sum[maxn + 10], u[maxn + 10];
inline int max(int a, int b) { return a > b ?a : b; }
inline int min(int a, int b) { return a < b ?a : b; }
void Mobius() {
memset(check, 0, sizeof(check));
mu[1] = 1;
int tot = 0;
for (int i = 2; i <= maxn; ++i) {
if (!check[i]) {
prime[tot++] = i;
mu[i] = -1;
}
for (int j = 0; j < tot; ++j) {
if (i * prime[j] > maxn) break;
check[i * prime[j]] = true;
if (i % prime[j] == 0) {
mu[i * prime[j]] = 0;
break;
}
else {
mu[i * prime[j]] = -mu[i];
}
}
}
}
void init() {
for (int j = 1; j <= maxn; ++j) {
g[j] += 1; g[j + 1] -= 1;
int lim = ceil(1.0 * maxn / j);
for (int k = 2; k <= lim; ++k) {
int w = k * j;
g[w - j + 1] += k, g[w-j+1] %= mod;
if (w + 1 <= maxn) g[w + 1] = (g[w+1] + mod - k) % mod;
}
}
for (int i = 1; i <= maxn; ++i) g[i] += g[i - 1], g[i] %= mod;
for (int i = 1; i <= maxn; ++i) sum[i] = sum[i-1] + g[i], sum[i] %= mod;
for (int i = 1; i <= maxn; ++i) u[i] = u[i-1] + mu[i];
}
void work() {
LL ans = 0;
int le, ri;
for (int i = 1; i <= n; i = ri + 1) {
le = i, ri = n / (n / i);
ans = (ans + (u[ri] - u[le - 1] + mod) % mod * sum[n / i] % mod) % mod;
}
printf("%lld\n", ans);
}
int main() {
Mobius(); init();
while (scanf("%d", &n) != EOF) work();
return 0;
}