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);
    }
}
posted @ 2020-09-16 13:00  Karry5307  阅读(216)  评论(1编辑  收藏  举报