koishi的数学题

洛咕

题意:输入一个整数\(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} \rfloor*i\).

所以设\(f[x]=\sum_{i=1}^x x-\lfloor \frac{x}{i} \rfloor*i\)

把前面的\(x\)提出来,\(f[x]=x^2-\sum_{i=1}^x \lfloor \frac{x}{i} \rfloor*i\)

\(g[x]=\sum_{i=1}^x \lfloor \frac{x}{i} \rfloor*i\),则\(f[x]=x^2-g[x]\)

来考虑一下如何求\(g[x]?\)(以下的分析很套路,碰到类似的取模问题,都可以这样找到规律),当\(i\)不变时,\(\lfloor \frac{x}{i} \rfloor\)不等于\(\lfloor \frac{x+1}{i} \rfloor\),当且仅当\(i\)\(x+1\)的约数.即当\(i\)\(x+1\)的约数时,\(\lfloor \frac{x+1}{i} \rfloor=\lfloor \frac{x}{i} \rfloor+1\),则\(\lfloor \frac{x+1}{i} \rfloor*i=\lfloor \frac{x}{i} \rfloor*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;
}

posted on 2019-10-24 19:30  PPXppx  阅读(190)  评论(0编辑  收藏  举报