题目链接
【分析】
- 就是求 Σ i = 1 n < n > i \Sigma_{i=1}^n <n>_i Σi=1n<n>i
- 与除法分块相同,但是数据范围更小,查询次数更多
- 考虑递推求解
- 设 f ( n ) = Σ i = 1 n < n > i f(n)=\Sigma_{i=1}^{n}<n>_i f(n)=Σi=1n<n>i
- 则 f ( n − 1 ) = Σ i − 1 n − 1 < n − 1 > i f(n-1)=\Sigma_{i-1}^{n-1}<n-1>_i f(n−1)=Σi−1n−1<n−1>i
- 不考虑 n ≡ 0 ( m o d n \equiv 0(mod n≡0(mod i ) i) i)的情况, f ( n ) = f ( n − 1 ) + ( n − 1 ) f(n)=f(n-1)+(n-1) f(n)=f(n−1)+(n−1)
- 当 n ≡ 0 ( m o d n \equiv 0(mod n≡0(mod i ) i) i)时,对 f ( n ) f(n) f(n)的贡献为 − ( σ ( n ) − n ) -(\sigma(n)-n) −(σ(n)−n)
- 所以 f ( n ) = f ( n − 1 ) + ( n − 1 ) − ( σ ( n ) − n ) f(n)=f(n-1)+(n-1)-(\sigma(n)-n) f(n)=f(n−1)+(n−1)−(σ(n)−n)
- σ \sigma σ可以用线性筛求出
【代码】
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;
const int N = 1e7 + 10;
int T, n;
int p[N], pr;
LL sigma[N], f[N], low[N];
void sieve(int n) {
sigma[1] = 1;
for (int i = 2; i <= n; ++i) {
if (low[i] == 0) {
low[i] = p[++pr] = i;
sigma[i] = i + 1;
}
for (int j = 1, k = i * p[j]; j <= pr && k <= n; ++j, k = i * p[j]) {
if (i % p[j] == 0) {
low[k] = low[i] * p[j];
if (low[k] == k)
sigma[k] = (low[k] * p[j] - 1) / (p[j] - 1);
else
sigma[k] = sigma[i / low[i]] * sigma[low[i] * p[j]];
break;
} else {
low[k] = p[j];
sigma[k] = sigma[i] * sigma[p[j]];
}
}
}
for (int i = 1; i <= n; ++i)
f[i] = f[i - 1] + (i - 1) - (sigma[i] - i);
}
int main() {
sieve(10000000);
scanf("%d", &T);
for (int i = 1; i <= T; ++i) {
scanf("%d", &n);
printf("%lld\n", f[n]);
}
return 0;
}