【51nod1220】約數之和

題目

d(k)表示k的所有約數的和。d(6) = 1 + 2 + 3 + 6 = 12。
定義S(N) = ∑1<=i<=N ∑1<=j<=N d(i*j)。
例如:S(3) = d(1) + d(2) + d(3) + d(2) + d(4) + d(6) + d(3) + d(6) + d(9) = 59,S(1000) = 563576517282。
給出正整數N,求S(N),由於結果可能會很大,輸出Mod 1000000007(10^9 + 7)的結果。

分析

分開處理每個質因子,於是d(ij)=p|iq|jiqp[gcd(p,q)=1]

ans=i=1nj=1np|iq|jiqp[gcd(p,q)=1]

上一波反演,
=d=1nμ(d)i=1nj=1np|iq|jiqp[d|gcd(p,q)]

=d=1nμ(d)p|iq[jqpp[iiq[j

=d=1nμ(d)p|iq[jqpnqpnp(np+1)2

=d=1nμ(d)d(p=1ndqndq)(q=1ndndp(ndp+1)2)

考慮處理ndq=1ndp(ndp+1)2
n 代替nd

i=1nni(ni+1)2

=i=1nj=1nij

=j=1nji=1nj

=j=1njnj(j=1nd(j))

ans=d=1nμ(d)d(p=1ndqndq)2

於是對於兩層 都分塊處理
類似與【51nod 2026】Gcd and Lcm,可以用杜教篩處理μ(d)d 的前綴和。
對於nj=1jnj ,直接上分塊。
#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
const int maxlongint=2147483647;
const long long mo=1e9+7;
const int lim=1e5+7;
const int N=10000005;
using namespace std;
#define sqr(x) (1ll*(x)*(x)%mo)
#define val(x,y) (1ll*(y-x+1)*(x+y)/2%mo)
int p[N],mu[N],n,ha[lim+5][2],s[N],ans;
bool bz[N];
int get(int v)
{
    int x;
    for(x=v%lim;ha[x][0] && ha[x][0]!=v;(++x)-=x>=lim?lim:0);
    return x;
}
int S(int m)
{
    if(m<=N-5) return s[m];
    int pos=get(m);
    if(ha[pos][0]) return ha[pos][1];
    ha[pos][0]=m;
    int la=0,sum=0;
    for(int i=2;i<=m;i=la+1)
    {
        la=m/(m/i);
        sum=(1ll*sum+1ll*val(i,la)*S(m/i))%mo;
    }
    return ha[pos][1]=(1-sum+mo)%mo;
}
int main()
{
    scanf("%d",&n);
    mu[1]=s[1]=1;
    for(int i=2;i<=N-5;i++)
    {
        if(!bz[i]) mu[p[++p[0]]=i]=-1;
        s[i]=(s[i-1]+mu[i]*i+mo)%mo;
        for(int j=1,k;j<=p[0] && (k=i*p[j])<=N-5;j++)
        {
            bz[k]=true;
            if(i%p[j]==0) break;
            mu[k]=-mu[i];
        }
    }
    int la=1;
    for(int i=1;i<=n;i=la+1)
    {
        la=n/(n/i);
        int last=1,nn=n/i,sum=0;
        for(int j=1;j<=nn;j=last+1)
        {
            last=nn/(nn/j);
            sum=(1ll*sum+1ll*(val(j,last))*(nn/j))%mo;
        }
        ans=(1ll*ans+1ll*(S(la)-S(i-1)+mo)*sqr(sum))%mo;
    }
    printf("%d",ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章