51Nod1227 平均最小公倍数

1227 平均最小公倍数

Lcm(a,b)表示a和b的最小公倍数,A(n)表示Lcm(n,i)的平均数(1 <= i <= n),
例如:A(4) = (Lcm(1,4) + Lcm(2,4) + Lcm(3,4) + Lcm(4,4)) / 4 = (4 + 4 + 12 + 4) / 4 = 6。
F(a, b) = A(a) + A(a + 1) + ...... A(b)。(F(a,b) = ∑A(k), a <= k <= b)
例如:F(2, 4) = A(2) + A(3) + A(4) = 2 + 4 + 6 = 12。
给出a,b,计算F(a, b),由于结果可能很大,输出F(a, b) % 1000000007的结果即可。

输入

输入2个数a,b,中间用空格分隔(1 <= a <= b <= 10^9)。

输出

输出F(a, b) % 1000000007的结果。

输入样例

1 100

输出样例

122726

题解

\[ A(n)=\frac 1n\sum_{i=1}^n\textrm{lcm(i,n)}=\frac 1n\sum_{i=1}^n\frac{in}{\gcd(i,n)}\\ =\sum_{i=1}^n\frac i{\gcd(i,n)}\\ =\sum_{d|n}\sum_{i=1}^{\frac nd}i[\gcd(i,\frac nd)=1] \]

根据公式\(\sum_{i=1}^ni[\gcd(i,n)=1]=\frac{n\varphi(n)+e(n)}{2}\),化简可得
\[ A(n)=\sum_{d|n}\frac{\frac nd\varphi(\frac nd)+e(\frac nd)}2\\ \frac 12(\sum_{d|n}d\varphi(d)+1)\\ F(n)=\sum_{i=1}^nA(n)=\sum_{i=1}^n\frac 12(\sum_{d|i}d\varphi(d)+1)\\ =\frac 12\left(\sum_{i=1}^n\sum_{d|i}d\varphi(d)+n\right) \]
\(d\varphi(d)\)就是\(id\cdot \varphi\),看起来非常眼熟。所以使用杜教筛套路,把枚举约数改为枚举倍数
\[ F(n)=\frac 12\left(\sum_{i=1}^n\sum_{k=1}^{\lfloor\frac ni\rfloor}k\varphi(k)+n\right) \]
令\(f(n)=n\varphi(n)\),它的前缀和\(S(n)=\sum_{i=1}^nf(i)\)。则
\[ F(n)=\frac 12\left(\sum_{i=1}^nS(\lfloor\frac ni\rfloor)+n\right) \]
只要能求出\(S\)就可以整除分块。于是构造\(g=id\),则
\[ (f*g)(n)=\sum_{d|n}f(n)g(\frac nd)=\sum_{d|n}d\varphi(d)\frac nd\\ =n\sum_{d|n}\varphi(d)=n^2 \]
至此问题解决,上杜教筛即可。时间复杂度\(O(n^\frac 23)\)

#include<bits/stdc++.h>
#define il inline
#define co const
template<class T>T read(){
    T data=0,w=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-') w=-w;
    for(;isdigit(ch);ch=getchar()) data=data*10+ch-'0';
    return data*w;
}
template<class T>il T read(T&x) {return x=read<T>();}
typedef long long LL;
using namespace std;

co int N=1e6+1,mod=1e9+7,i2=500000004,i6=166666668;
il int add(int a,int b){
    return (a+=b)>=mod?a-mod:a;
}
il int mul(int a,int b){
    return (LL)a*b%mod;
}
int pri[N],tot,phi[N];
void init(){
    pri[1]=phi[1]=1;
    for(int i=2;i<N;++i){
        if(!pri[i]) pri[++tot]=i,phi[i]=i-1;
        for(int j=1;j<=tot&&i*pri[j]<N;++j){
            pri[i*pri[j]]=1;
            if(i%pri[j]==0){
                phi[i*pri[j]]=phi[i]*pri[j];
                break;
            }
            phi[i*pri[j]]=phi[i]*phi[pri[j]];
        }
    }
    for(int i=2;i<N;++i) phi[i]=add(phi[i-1],mul(phi[i],i));
}
map<int,int> sf;
int sum_f(int n){
    if(n<N) return phi[n];
    if(sf.count(n)) return sf[n];
    int ans=mul(i6,mul(n,mul(n+1,2*n+1)));
    for(int l=2,r;l<=n;l=r+1){
        r=n/(n/l);
        ans=add(ans,mod-mul(mul(i2,mul(l+r,r-l+1)),sum_f(n/l)));
    }
    return sf[n]=ans;
}
int solve(int n){
    int ans=n;
    for(int l=1,r;l<=n;l=r+1){
        r=n/(n/l);
        ans=add(ans,mul(r-l+1,sum_f(n/l)));
    }
    return mul(i2,ans);
}
int main(){
    init();
    int a=read<int>(),b=read<int>();
    printf("%d\n",add(solve(b),mod-solve(a-1))); // edit 1:mod
    return 0;
}
上一篇:P1084 疫情控制


下一篇:[NOI2018] 你的名字