【51nod 1227】 平均最小公倍数(杜教筛)

题目来源: Project Euler
基准时间限制:1.5 秒 空间限制:131072 KB 分值: 640 难度:8级算法题 重点内容
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的结果即可。
Input
输入2个数a,b,中间用空格分隔(1 <= a <= b <= 10^9)。
Output
输出F(a, b) % 1000000007的结果。
Input示例
1 100
Output示例
122726

推吧。我们先看 A(n) A ( n ) .

A(n)=1ni=1nlcm(i,n)=i=1igcd(i,n) A ( n ) = 1 n ∑ i = 1 n l c m ( i , n ) = ∑ i = 1 i g c d ( i , n )

我们枚举gcd:
A(n)=d|nd|i[gcd(i,n)==d]id=d|nd|i[gcd(id,nd)==1]id=d|nind[gcd(i,nd)==1]i A ( n ) = ∑ d | n ∑ d | i [ g c d ( i , n ) == d ] i d = ∑ d | n ∑ d | i [ g c d ( i d , n d ) == 1 ] i d = ∑ d | n ∑ i n d [ g c d ( i , n d ) == 1 ] i

这里可以引入欧拉函数了:
A(n)=12+d|ndϕ(d)2 A ( n ) = 1 2 + ∑ d | n d ϕ ( d ) 2

设:

F(n)=n2+12i=1nj|ijϕ(j) F ( n ) = n 2 + 1 2 ∑ i = 1 n ∑ j | i j ϕ ( j )

设:
F(n)=i=1nj|ijϕ(j)=j=1njϕ(j)nj F ′ ( n ) = ∑ i = 1 n ∑ j | i j ϕ ( j ) = ∑ j = 1 n j ϕ ( j ) ⌊ n j ⌋

这里就很显然了,用杜教筛搞 jϕ(j) j ϕ ( j ) 的前缀和,然后分块求答案。
f(x)=xϕ(x),g(x)=x f ( x ) = x ϕ ( x ) , g ( x ) = x ,这两个函数搞一下卷积。

fg(n)=d|ndϕ(d)nd=n2 f ∗ g ( n ) = ∑ d | n d ϕ ( d ) n d = n 2

sum(n)=i=1niϕ(i) s u m ( n ) = ∑ i = 1 n i ϕ ( i )

推得:

sum(n)=(n+1)n(2n+1)6i=2nisum(ni) s u m ( n ) = ( n + 1 ) n ( 2 n + 1 ) 6 − ∑ i = 2 n i ∗ s u m ( ⌊ n i ⌋ )

代码:

#include
#include
#include
#include
#include
#include
#define maxx 5000000
#define mod 1000000007
#define ll long long
using namespace std;
bool isP[maxx];
int prime[400000];
int cnt;
ll phi[maxx];
ll sum[maxx];
ll inv2=500000004,inv6=166666668;
void init()
{
    phi[1]=1;
    for(int i=2;iif(!isP[i])
        {
            prime[cnt++]=i;
            phi[i]=i-1;
        }
        for(int j=0;j*prime[j]*prime[j]]=true;
            if(i%prime[j])
                phi[i*prime[j]]=phi[i]*(prime[j]-1);
            else
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
        }
    }
    for(int i=1;i*phi[i]%mod;
    for(int i=1;i1])%mod;
}
mapM;
ll get(ll a,ll b)
{
    return (b-a+1)*(b+a)%mod*inv2%mod;
}
ll work(ll x)
{
    if(xreturn sum[x];
    if(M[x])return M[x];
    ll t=x%mod;
    ll ans=t*(t+1)%mod*(2*t%mod+1)%mod*inv6%mod;
    for(ll i=2,last;i<=x;i=last+1)
    {
        last=x/(x/i);
        ans=(ans-get(i,last)*work(x/i)%mod)%mod;
    }
    if(ans<0)ans=(ans+mod)%mod;
    M[x]=ans;
    return ans;
}
ll F(ll x)
{
    ll ans=0;
    for(ll i=1,last;i<=x;i=last+1)
    {
       last=x/(x/i);
       ll now=(work(last)-work(i-1)+mod)%mod;
       ll base=x/i%mod;
       ans=(ans+base*now%mod)%mod;
    }
    ans=ans*inv2%mod;
    ans=(ans+x*inv2%mod)%mod;
    return ans;
}
int main()
{
    init();
    ll a,b;
    cin>>a>>b;
    cout<<(F(b)-F(a-1)+mod)%mod<return 0;
}

你可能感兴趣的:(数论,杜教筛)