Luogu P3708 koishi的数学题
题意
给定整数 \(n\),设 \(f(x)=\sum\limits_{i=1}^{n}x\bmod i\),对于 \(1\leq i\leq n\) 求 \(f(i)\)。
\(\texttt{Data Range:}1\leq n\leq 10^6\)
题解
做完这题之后看了一下题解区,都写的啥啊,来写篇思路清晰点的。
考虑推下式子:
\[\sum\limits_{i=0}^{n}x\bmod i=nx-\sum\limits_{i=1}^{n}i\left\lfloor\frac{x}{i}\right\rfloor
\]
接下来考虑差分:
\[\sum\limits_{i=1}^{n}i\left(\left\lfloor\frac{x}{i}\right\rfloor-\left\lfloor\frac{x-1}{i}\right\rfloor\right)=\sum\limits_{i=1}^{n}i[i\mid x]=\sigma(x)
\]
所以
\[\sum\limits_{i=0}^{n}x\bmod i=nx-\sum\limits_{i=1}^{x}\sigma(i)
\]
线性筛出 \(\sigma(i)\) 的前缀和即可。
代码
#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long int li;
const ll MAXN=1e6+51;
ll n,ptot;
li cur;
ll np[MAXN],prime[MAXN],low[MAXN];
li sum[MAXN],sigma[MAXN];
inline ll read()
{
register ll num=0,neg=1;
register char ch=getchar();
while(!isdigit(ch)&&ch!='-')
{
ch=getchar();
}
if(ch=='-')
{
neg=-1;
ch=getchar();
}
while(isdigit(ch))
{
num=(num<<3)+(num<<1)+(ch-'0');
ch=getchar();
}
return num*neg;
}
inline void sieve(ll limit)
{
np[1]=low[1]=sum[1]=sigma[1]=1;
for(register int i=2;i<=limit;i++)
{
if(!np[i])
{
prime[++ptot]=i,low[i]=i,sum[i]=sigma[i]=i+1;
}
for(register int j=1;i*prime[j]<=limit;j++)
{
np[i*prime[j]]=1;
if(i%prime[j]==0)
{
low[i*prime[j]]=low[i]*prime[j];
sum[i*prime[j]]=sum[i]+low[i*prime[j]];
sigma[i*prime[j]]=sigma[i]/sum[i]*sum[i*prime[j]];
break;
}
low[i*prime[j]]=prime[j],sum[i*prime[j]]=prime[j]+1;
sigma[i*prime[j]]=sigma[i]*sigma[prime[j]];
}
}
}
int main()
{
sieve(n=read());
for(register int i=1;i<=n;i++)
{
cur+=sigma[i],printf("%lld ",(li)i*n-cur);
}
}