洛谷传送门
题目描述
Koishi在Flandre的指导下成为了一名数学大师,她想了一道简单的数学题。
输入一个整数n,设 f(x)=∑ni=1x mod i f ( x ) = ∑ i = 1 n x m o d i ,你需要输出 f(1),f(2)...f(n) f ( 1 ) , f ( 2 ) . . . f ( n ) 。
按照套路,Koishi假装自己并不会做这道题,就来求你帮忙辣。
输入输出格式
输入格式:
一个正整数 n n 。
输出格式:
一行用空格分隔的 个整数 f(1),f(2)...f(n) f ( 1 ) , f ( 2 ) . . . f ( n ) 。
输入输出样例
输入样例#1:
10
输出样例#1:
9 16 22 25 29 27 29 24 21 13
说明
对于20%的数据, n≤1000 n ≤ 1000 。
对于60%的数据, n≤105 n ≤ 10 5 。
对于100%的数据, 1≤n≤106 1 ≤ n ≤ 10 6 。
解题分析
首先, 我们构造一组样例观察一下: 设
n=10
n
=
10
f(9) f ( 9 ) 中绝大多数项都比 f(8) f ( 8 ) 大1, 那么我们就先每项添1
然后我们发现那些不比
f(8)
f
(
8
)
大1的项都为0, 恰好又是
9
9
的因数, 所以可以得到一下递推式:
。
所以线筛+递推, 总复杂度 O(n) O ( n ) 。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <cstdlib>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define MX 1000500
#define ll long long
int pri[MX];
ll sum[MX], sgm[MX], ans[MX];
bool npr[MX];
int n, pcnt;
void getsigma0()
{
R int j, tar;
sgm[1] = sum[1] = 1;
for (R int i = 2; i <= n; ++i)
{
if(!npr[i]) sum[i] = sgm[i] = i + 1, pri[++pcnt] = i;
for (j = 1; j <= pcnt; ++j)
{
tar = pri[j] * i;
if(tar > n) break;
npr[tar] = true;
if(!(i % pri[j])) {sum[tar] = pri[j] * sum[i] + 1, sgm[tar] = sgm[i] * sum[tar] / sum[i]; break;}
else sum[tar] = 1 + pri[j], sgm[tar] = sgm[i] * sum[tar];
}
}
}
int main(void)
{
scanf("%d", &n);
getsigma0();
ans[1] = n - 1; printf("%lld ", ans[1]);
for (R int i = 2; i <= n; ++i) ans[i] = ans[i - 1] + n - sgm[i], printf("%lld ", ans[i]);
}