题意:输入一个整数(n),设(f(x)=sum_{i=1}^n x~mod~i),你需要输出(f(1),f(2)...f(n)).(n<=1e6.)
因为当(i>x)时,(x~mod~ i=x),这一部分可以直接(O(1))计算.所以先不管.(产生的贡献是(x*(n-x)))
分析:分析取模的性质/规律的时候有一个常用套路:(x~mod~i=x-lfloor frac{x}{i}
floor*i).
所以设(f[x]=sum_{i=1}^x x-lfloor frac{x}{i}
floor*i)
把前面的(x)提出来,(f[x]=x^2-sum_{i=1}^x lfloor frac{x}{i}
floor*i)
设(g[x]=sum_{i=1}^x lfloor frac{x}{i}
floor*i),则(f[x]=x^2-g[x])
来考虑一下如何求(g[x]?)(以下的分析很套路,碰到类似的取模问题,都可以这样找到规律),当(i)不变时,(lfloor frac{x}{i}
floor)不等于(lfloor frac{x+1}{i}
floor),当且仅当(i)是(x+1)的约数.即当(i)是(x+1)的约数时,(lfloor frac{x+1}{i}
floor=lfloor frac{x}{i}
floor+1),则(lfloor frac{x+1}{i}
floor*i=lfloor frac{x}{i}
floor*i+i).所以(g[x+1]=g[x]+sum[x]),其中(sum[x])表示(x)的约数和.
综上,预处理出每个数的约数和,这个可以用倍数法在(nlogn)的时间内做到,然后就是线性递推求(g)数组,然后对于每一个(x),(ans=x^2-g[x]+x*(n-x)).
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=1e6+5;
ll sum[N],g[N];
int main(){
int n=read();
for(int i=1;i<=n;++i)
for(int j=1;j*i<=n;++j)sum[i*j]+=i;
for(int i=1;i<=n;++i)g[i]=g[i-1]+sum[i];
for(int i=1;i<=n;++i)printf("%lld ",1ll*i*i-g[i]+1ll*i*(n-i));
return 0;
}