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} 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;
}

原文地址:https://www.cnblogs.com/PPXppx/p/11734330.html