51Nod 1227 平均最小公倍数(杜教筛)

题目链接:哆啦A梦传送门

题意:

∑ i = a b 1 i ∑ j = 1 i l c m ( j , i ) \begin{aligned}\sum_{i=a}^{b}\frac{1}{i}\sum_{j=1}^{i}lcm(j,i)\end{aligned} i=abi1j=1ilcm(j,i)

我们设:

a n s = ∑ i = 1 n 1 i ∑ j = 1 i l c m ( j , i ) = ∑ i = 1 n 1 i ∑ j = 1 i i ∗ j g c d ( i , j ) = ∑ d = 1 n d ∑ i = 1 n d 1 i ∗ i ∑ j = 1 i [ g c d ( i , j ) = 1 ] j = ∑ d = 1 n d ∑ i = 1 n d i ∗ φ ( i ) + [ n = = 1 ] 2 = ( 1 2 ∑ d = 1 n d ∑ i = 1 n d i ∗ φ ( i ) ) + n 2 \begin{aligned}ans&=\sum_{i=1}^{n}\frac{1}{i}\sum_{j=1}^{i}lcm(j,i)\\ &=\sum_{i=1}^{n}\frac{1}{i}\sum_{j=1}^{i}\frac{i*j}{gcd(i,j)}\\ &=\sum_{d=1}^{n}d\sum_{i=1}^{\frac{n}{d}}\frac{1}{i}*i\sum_{j=1}^{i}[gcd(i,j)=1]j\\ &=\sum_{d=1}^{n}d\sum_{i=1}^{\frac{n}{d}}\frac{i*\varphi(i)+[n==1]}{2}\\ &=(\frac{1}{2}\sum_{d=1}^{n}d\sum_{i=1}^{\frac{n}{d}}i*\varphi(i))+\frac{n}{2}\end{aligned} ans=i=1ni1j=1ilcm(j,i)=i=1ni1j=1igcd(i,j)ij=d=1ndi=1dni1ij=1i[gcd(i,j)=1]j=d=1ndi=1dn2iφ(i)+[n==1]=(21d=1ndi=1dniφ(i))+2n

现在我们看到这个式子,只需分块计算,但我们还得快速得出 ∑ i = 1 n i ∗ φ ( i ) \begin{aligned}\sum_{i=1}^{n}i*\varphi(i)\end{aligned} i=1niφ(i)

我们知道有一个关于 φ ( i ) \varphi(i) φ(i)的性质:
n = ∑ d ∣ n φ ( d ) n=\sum_{d|n}\varphi(d) n=dnφ(d)

那么我们设 h ( x ) = x ∗ φ ( x ) h(x)=x*\varphi(x) h(x)=xφ(x) S ( n ) = ∑ i = 1 n h ( i ) S(n)=\sum_{i=1}^{n}h(i) S(n)=i=1nh(i)

我们知道: ∑ i = 1 n i 2 = n ∗ ( n + 1 ) ∗ ( 2 ∗ n + 1 ) 6 \sum_{i=1}^{n}i^2=\frac{n*(n+1)*(2*n+1)}{6} i=1ni2=6n(n+1)(2n+1)
即:

∑ i = 1 n i 2 = ∑ d = 1 n ∑ i ∣ d φ ( i ) ∗ d = ∑ d = 1 n ∑ i ∣ d h ( i ) ∗ d i = ∑ d = 1 n ∑ i = 1 n d h ( i ) ∗ ( d ∗ i ) i = ∑ d = 1 n d ∑ i = 1 n d h ( i ) \begin{aligned}\sum_{i=1}^{n}i^2&=\sum_{d=1}^{n}\sum_{i|d}\varphi(i)*d\\ &=\sum_{d=1}^{n}\sum_{i|d}h(i)*\frac{d}{i}\\ &=\sum_{d=1}^{n}\sum_{i=1}^{\frac{n}{d}}h(i)*\frac{(d*i)}{i}\\ &=\sum_{d=1}^{n}d\sum_{i=1}^{\frac{n}{d}}h(i)\end{aligned} i=1ni2=d=1nidφ(i)d=d=1nidh(i)id=d=1ni=1dnh(i)i(di)=d=1ndi=1dnh(i)

即:
n ∗ ( n + 1 ) ∗ ( 2 ∗ n + 1 ) 6 = S ( n ) + ∑ d = 2 n d ∑ i = 1 n d h ( i ) \begin{aligned}\frac{n*(n+1)*(2*n+1)}{6}=S(n)+\sum_{d=2}^{n}d\sum_{i=1}^{\frac{n}{d}}h(i)\end{aligned} 6n(n+1)(2n+1)=S(n)+d=2ndi=1dnh(i)
S ( n ) = n ∗ ( n + 1 ) ∗ ( 2 ∗ n + 1 ) 6 − ∑ d = 2 n d ∑ i = 1 n d h ( i ) \begin{aligned}S(n)=\frac{n*(n+1)*(2*n+1)}{6}-\sum_{d=2}^{n}d\sum_{i=1}^{\frac{n}{d}}h(i)\end{aligned} S(n)=6n(n+1)(2n+1)d=2ndi=1dnh(i)

故我们可以预处理前6000000现 x ∗ φ ( x ) x*\varphi(x) xφ(x)和。再分块计算就好了。



#include<cstdio>
#include<algorithm>
#include<cstring>
#include<tr1/unordered_map>

using namespace std;
typedef long long LL;
const LL mod=1000000007;
const int N=6e6;

LL sum[N];///存放S的前N项
bool vis[N+10];
LL phi[N+10];
int pri[N+10],tot;

tr1::unordered_map<LL,LL> w;

LL inv2,inv4,inv6;

void init()
{


    phi[1]=1;

    for(int i=2;i<=N;i++)
    {
        if(!vis[i]){
            phi[i]=i-1;
            pri[++tot]=i;
        }
        for(int j=1;j<=tot&&i*pri[j]<=N;j++)
        {
            int t=pri[j];
            vis[i*t]=1;
            if(i%t==0){
                phi[i*t]=phi[i]*t;break;
            }
            phi[i*t]=phi[i]*(t-1);
        }
    }

    ///预处理 \sum_{i=1}^{N}i*phi[i]
    for(int i=1;i<=N;i++)
    {
        sum[i]=(sum[i-1]+1LL*phi[i]%mod*i%mod)%mod;
    }

}

LL fast_pow(LL a1,LL n)
{
    LL ans=1;
    while(n)
    {
        if(n&1) ans=ans*a1%mod;
        a1=a1*a1%mod;
        n>>=1;
    }
    return ans;
}

LL s2(LL x) ///\sum_{i=1}^{x}i*i
{
    LL t=x%mod;
    return t*(t+1)%mod*(2*t+1)%mod*inv6%mod;
}

LL s1(LL x) ///\sum_{i=1}^{x}i
{
    x=x%mod;
    return x*(x+1)%mod*inv2%mod;
}


LL djs(LL x)
{
    if(x<=N) return sum[x];
    if(w[x]) return w[x];

    LL t=x%mod;
    LL ans=s2(x);
    for(LL l=2,r;l<=x;l=r+1)
    {
        r=x/(x/l);
        ans=(ans-(s1(r)-s1(l-1)+mod)%mod*djs(x/l)+mod)%mod;
    }

    return w[x]=ans;


}

LL solve(LL n)
{

    LL ans=n%mod;
    for(LL l=1,r;l<=n;l=r+1)
    {
        r=n/(n/l);
        ans=(ans+(r-l+1+mod)%mod*djs(n/l)%mod)%mod;
    }

    return ans*inv2%mod;
}



int main()
{

    LL n;

     inv2=fast_pow((LL)2,mod-2);
     inv4=fast_pow((LL)4,mod-2);
     inv6=fast_pow((LL)6,mod-2);

    init();
    LL a,b;

    scanf("%lld%lld",&a,&b);

    LL ans=0;

    ans=(solve(b)-solve(a-1)+mod)%mod;


    printf("%lld\n",ans);

    return 0;
}


\begin{aligned}\end{aligned}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值