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 <stdio.h>
#include <algorithm>
#include <string.h>
#include <cmath>
#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<SQR;i++)Iv[i]=(P-(LL)Iv[P%i]*(P/i)%P)%P;
    for(int i=1;i<MAXN;i++)
    {
        phi[i]=i-phi[i];
        for(int j=i<<1;j<MAXN;j+=i)phi[j]+=phi[i];
        phi[i]=(LL)phi[i]*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<MAXN)
            ans+=(LL)g[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(n<MAXN)return ;
    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(u1<MAXN)
            u1=g[u1];
        else
            u1=tmp[L];
        if(u2<MAXN)
            u2=g[u2];
        else
            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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值