51nod1238 最小公倍数之和 V3

题解

  感觉柿子画起来有点费劲,我太蒻了。

ans=i=1nj=1nij(i,j)=d=1n1dd|ind|jnij[(i,j)=1]=d=1ndi=1ndj=1ndij[(i,j)=1]=d=1nd×(2i=1ndi(j=1ij[(i,j)=1]))1)=d=1nd(2i=1ndiiφ(i)+[i=1]21)=d=1ndi=1ndi2φ(i)

  令 f(i)=i2φ(i) s(n)=ni=1f(i)
ans=d=1nd×s(nd)

   id2(n)=n2
d|nd2φ(i)id2(nd)=d|nd2φ(i)n2d2=n3

  要画出杜教筛,要试着对卷积求个前缀和
i=1nd|if(d)id2(id)=id=1nd=1nidf(d)id2(id)=t=1nd=1ntf(d)id2(t)=t=1nid2(t)s(nt)

  因为强迫症,我把 t 都换成 i 。(和之前的 i 没有任何关系)
i=1nid2(i)s(ni)=i=1ni3s(n)=i=1ni3i=2nid2(i)s((ni)

  好了

代码

//杜教筛 
#include <cstdio>
#include <algorithm>
#define maxn 4700000
#define mod 1000000007ll
using namespace std;
typedef long long ll;
ll f[maxn+10], phi[maxn+10], _2, _6, N;
int prime[maxn+10];
bool mark[maxn+10];
void shai()
{
    ll i, j;
    phi[1]=1;
    for(i=2;i<maxn;i++)
    {
        if(!mark[i])prime[++*prime]=i, phi[i]=i-1;
        for(j=1;i*prime[j]<maxn;j++)
        {
            mark[i*prime[j]]=1;
            if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j];break;}
            phi[i*prime[j]]=phi[i]*phi[prime[j]];
        }
    }
    for(i=1;i<maxn;i++)phi[i]=(phi[i]*i%mod*i%mod+phi[i-1])%mod;
}
ll sqr(ll x){if(x>mod)x%=mod;return x*x%mod;}
ll s1(ll x){if(x>mod)x%=mod;return x*(1+x)%mod*_2%mod;}
ll s2(ll x){if(x>mod)x%=mod;return x*(1+x)%mod*(2*x+1)%mod*_6%mod;}
ll s3(ll x){if(x>mod)x%mod;return sqr(s1(x));}
ll getf(ll x){return x<maxn?phi[x]:f[N/x];}
void djs(ll n)
{
    if(n<maxn or getf(n))return;
    ll i, last, t=N/n;
    f[t]=s3(n);
    for(i=2;i<=n;i=last+1)
    {
        last=n/(n/i);
        djs(n/i);
        f[t]=(f[t]-(s2(last)-s2(i-1))*getf(n/i)%mod)%mod;
    }
}
int main()
{
    ll i, last, ans=0;
    _2=500000004;
    _6=166666668;
    scanf("%lld",&N);
    shai();
    djs(N);
    for(i=1;i<=N;i=last+1)
    {
        last=N/(N/i);
        ans=(ans+getf(N/i)*(s1(last)-s1(i-1)))%mod;
    }
    printf("%lld",(ans+mod)%mod);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/fsahfgsadhsakndas/article/details/71799194