51nod 1227 平均最小公倍数

51nod 1227 平均最小公倍数

原题链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1227

A(n)=1ni=1nlcm(i,n)

k=1nA(k)=k=1n1ki=1klcm(i,k)=k=1n1ki=1kkigcd(i,k)=k=1ni=1kigcd(i,k)=k=1nd|ki=1kid[gcd(i,k)=d]=k=1nd|ki=1kdi[ikd]

对于计算 [1,n] 与n互素的数字之和可以类比等差数列的倒叙相加。

因为 an 则: (na)n

所以:
i=1n[in]i=φ(n)n2

特别的, n=1 时:
i=1n[in]i=φ(n)n+12

所以:
k=1nd|ki=1kdi[ikd]=k=1n(12+d|kφ(d)d2)=n2+12d=1nφ(d)dnd

令:
g(n)=φ(n)nidk(n)=nk

显而下面的狄利克雷积成立:
gid1=id2

f 的前缀和为: Sf

则:
Sg(n)=n(n+1)(2n+1)6i=2niSg(ni)

那么对于:
d=1nφ(d)dnd=L=1m1L(Sg(nL)Sg(nL+1))+d=1nmg(d)nd

代码:

#include 
#include 
#include 
#include 
#define MAXN 1000000
#define SQR 40000
#define S(a) ((LL)(a)*((a)+1)%P*Iv[2]%P)
using namespace std;
typedef long long LL;
const int P=1e9+7;
int tmp[SQR];
int g[MAXN];
int phi[MAXN];
int Iv[SQR];

void init ()
{
    Iv[1]=1;
    for(int i=2;i%i]*(P/i)%P)%P;
    for(int i=1;ifor(int j=i<<1;j*i%P;
        g[i]=phi[i]+g[i-1];
        if(g[i]>=P)g[i]-=P;
    }
}

void clat(int n,int d)
{
    int m=sqrt(n)+1,ans=0;
    for(int L=1;L<m;L++)
    {
        ans+=(LL)g[L]*((S(n/L)-S(n/(L+1))+P)%P)%P;
        if(ans>=P)ans-=P;
    }
    for(int i=n/m;i>1;i--)
    {
        int u=n/i;
        if(u*i%P;
        else
            ans+=(LL)tmp[i*d]*i%P;
        if(ans>=P)ans-=P;
    }
    m=(LL)n*(n+1)%P*(2*n+1)%P*Iv[6]%P;
    tmp[d]=(P+m-ans)%P;
}

void sum(int n)
{
    if(nreturn ;
    for(int i=n/MAXN;i;i--)clat(n/i,i);
    return ;
}

int solve(int n)
{
    sum(n);
    int m=sqrt(n)+1,ans=0;
    for(int L=1;L<m;L++)
    {
        int u1=n/L;
        int u2=n/(L+1);
        if(u1else
            u1=tmp[L];
        if(u2else
            u2=tmp[L+1];
        ans+=(LL)L*(u1-u2+P)%P;
        if(ans>=P)ans-=P;
    }
    for(int i=n/m;i;i--)
    {
        ans+=(LL)phi[i]*(n/i)%P;
        if(ans>=P)ans-=P;
    }
    return ans;
}

int main ()
{
    init();
    int a,b;
    scanf("%d %d",&a,&b);
    a--;
    int A=solve(a);
    int B=solve(b);
    A=(LL)A*Iv[2]%P;
    A+=(LL)a*Iv[2]%P;
    if(A>=P)A-=P;
    B=(LL)B*Iv[2]%P;
    B+=(LL)b*Iv[2]%P;
    if(B>=P)B-=P;
    printf("%d\n",(B-A+P)%P);
    return 0;
}

你可能感兴趣的:(刷题小结,数据结构,杜教筛,组合数学)