题目链接https://www.luogu.org/problemnew/show/P3708
样例解释
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
---|---|---|---|---|---|---|---|---|---|
0 | 0 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
0 | 1 | 0 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
0 | 0 | 1 | 0 | 4 | 4 | 4 | 4 | 4 | 4 |
0 | 1 | 2 | 1 | 0 | 5 | 5 | 5 | 5 | 5 |
0 | 0 | 0 | 2 | 1 | 0 | 6 | 6 | 6 | 6 |
0 | 1 | 1 | 3 | 2 | 1 | 0 | 7 | 7 | 7 |
0 | 0 | 2 | 0 | 3 | 2 | 1 | 0 | 8 | 8 |
0 | 1 | 0 | 1 | 4 | 3 | 2 | 1 | 0 | 9 |
0 | 0 | 1 | 2 | 0 | 4 | 3 | 2 | 1 | 0 |
很显然横行相加就是每个答案,然而观察纵行
1,0,1,0 120,120, 1230,1230。。。
每一纵行:对于每一个i,x递增时,x mod i是一个以i为循环周期的数列
处理这样的一个数列时间复杂度较高,但是经过观察发现x-(x mod i)当x递增时是一个每i项增加i的一个数列
于是要得到f(x),即可有f(x-1)+n-1,用一个flag数组标记它
即每i个数打一个标记,增加i
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200010;
long long n,ans;
long long flag[maxn];
int main()
{
scanf("%lld",&n);
for(int i=2;i<=n;i++)
{
for(int j=i;j<=n;j+=i)
{
flag[j]+=i;
}
}
for(int i=1;i<=n;i++)
{
ans+=n-flag[i]-1;
printf("%lld ",ans);
}
return 0;
}