51nod [1227 平均最小公倍数]

题意

求 $ \sum\limits_{i=l}^ r\dfrac{1}{i}\sum\limits_{j=1}^i\operatorname{lcm}(i,j) $ ,其中 $ 1\le l\le r\le 10^9 $ 。

题目链接

题解

众所周知, $ i\times j=\gcd(i,j)\times\operatorname{lcm}(i,j) $ 。

这个应该是小学只是了吧,我就不证了。(虽然我也不会比较严谨的证明)

加入我们要求一段区间的和,其实只需要能够求前缀就可以了。

所以我们来颓柿子。

欢乐的颓柿子时间

\[\begin{aligned} &\sum_{i=1}^n\dfrac{1}{i}\sum_{j=1}^i\operatorname{lcm}(i,j)\\ =&\sum_{i=1}^n\dfrac{1}{i}\sum_{j=1}^i\dfrac{i\times j}{\gcd(i,j)}&\textbf{使用刚才的公式}\\ =&\sum_{i=1}^n\sum_{j=1}^i\dfrac{j}{\gcd(i,j)}&\textbf{约分}\\ =&\sum_{d=1}^n\sum_{i=1}^n\sum_{j=1}^i\dfrac{j}{d}\times\left[\gcd(i,j)=d\right]&\textbf{枚举}\gcd\\ =&\sum_{d=1}^n\sum_{i=1}^{\left\lfloor\frac{n}{d}\right\rfloor}\sum_{j=1}^ij\times\left[\gcd(i,j)=1\right]&i,j\textbf{都是}d\textbf{的倍数,我们枚举他们是}d\textbf{的几倍}\\ \end{aligned} \]

令 $ h(n)=\sum\limits_{i=1}^ni\times [\gcd(i,n)=1] $ , $ S(n)=\sum\limits_{i=1}^nh(i) $ 。

那么上式 $ =\sum\limits_{d=1}^ n\sum\limits_{i=1}^ {\left\lfloor\frac{n}{d}\right\rfloor}h(i)=\sum\limits_{d=1}^nS\left(\left\lfloor\dfrac{n}{d}\right\rfloor\right) $ 。

如果可以快速求出 $ S(i) $ ,那么就可以直接数论分块了。

那么 $ h(n) $ 代表了什么呢?

不就是小于等于 $ n $ 的所有正整数中,和 $ n $ 互质的所有数的和嘛!

所以有 $ h(n)=\dfrac{n\times\varphi(n)+[n=1]}{2} $ 。

为什么是这样的呢?

当 $ n=1 $ 时,显然没问题, $ h(1)=1 $ 。

当 $ n\ge2 $ 时,如果 $ \gcd(i,n)=1 $ ,那么肯定也有 $ \gcd(n-i,i)=1 $ 。

这告诉我们什么?不就是所有小于等于 $ n $ 的数种中与 $ n $ 互质的数的平均数为 $ \dfrac{n}{2} $ 嘛!

小于等于 $ n $ 的数中与 $ n $ 互质的数共有 $ \varphi(n) $ 个,所以上面式子没啥问题。

好,那么我们令 $ f(i)=i\varphi(i) $ , $ S'(n)=\sum\limits_{i=1}^nf(i) $ 。

那么就有 $ S(n)=\dfrac{S'(n)+1}{2} $ 。

既然 $ f $ 是一个积性函数,并且数据范围为 $ 10^9 $ ,考虑使用杜教筛求解。

杜教筛

显然, $ f=id\cdot \varphi $ , 我们设 $ g=id $ ,下来搬出杜教筛的式子。

$ S(n)=\sum\limits_{i=1}^n(f\ast g)(i)-\sum\limits_{i=2}^n g(i)S\left(\left\lfloor\dfrac{n}{i}\right\rfloor\right) $ 。

$ f\ast g $ 又怎么求呢?

$ (f\ast g)(n)=\sum\limits_{d|n}f(d)g\left(\dfrac{n}{d}\right)=\sum\limits_{d|n}d\varphi(d)\times\dfrac{n}{d}=n\sum\limits_{d|n}\varphi(d)=n(\varphi\ast I)(n)=n\times id(n)=n^2 $。

这个直接求就可以了, $ g $ 更简单,就不说了。

代码

#include<unordered_map>
#include<cstdio>
using namespace std;
using ll=long long;
const int mod=1000000007;
const ll inv2=500000004;
const ll inv6=166666668;
inline int read()
{
    int s=0,w=1;char ch;
    while((ch=getchar())>'9'||ch<'0') if(ch=='-') w=-1;
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    return s*w;
}
unordered_map<int,ll>mf;
int pri[1000001];
bool is[1000001];
ll f[1000001];
int n;
ll run(int l,int r)
{
    return (ll)(r-l+1)*(l+r)/2%mod;
}
ll get(int n)
{
    if(n<=1000000) return f[n];
    if(mf.count(n)) return mf[n];
    ll ans=(ll)n*(n+1)%mod*(2*n+1)%mod*inv6%mod;
    for(int l=2,r;l<=n;l=r+1)
    {
        r=n/(n/l);
        ans=(ans-run(l,r)*get(n/l))%mod;
    }
    return mf[n]=(ans+mod)%mod;
}
ll getS(int n)
{
    ll ans=0;
    for(int l=1,r;l<=n;l=r+1)
    {
        r=n/(n/l);
        ans+=(r-l+1)*(get(n/l)+1)%mod*inv2%mod;
    }
    return ans%mod;
}
int main()
{
	// freopen("data.in","r",stdin);
    n=1000000,f[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!is[i]) pri[++pri[0]]=i,f[i]=i-1;
        for(int j=1;j<=pri[0]&&i*pri[j]<=n;j++)
        {
            is[i*pri[j]]=1;
            if(i%pri[j]==0)
            {
                f[i*pri[j]]=f[i]*pri[j];
                break;
            }
            f[i*pri[j]]=f[i]*(pri[j]-1);
        }
    }
    for(int i=1;i<=n;i++) f[i]=(f[i]*i+f[i-1])%mod;
    int l=read(),r=read();
    // for(int i=1;i<=n+1;i++) printf("%lld ",get(i));
    printf("%lld\n",(getS(r)-getS(l-1)+mod)%mod);
    return 0;
}
posted @ 2022-06-08 17:43  Wuyanru  阅读(44)  评论(0编辑  收藏  举报