51NOD 1227:平均最小公倍数——题解

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1227

懒得打公式了,看这位的吧:https://blog.csdn.net/fromatp/article/details/74999989

又一次将我的智商下限刷低的一道题,论我根本没注意到[gcd(i,j)==1]*j=phi(i)*i/2这个悲催的事实。

果然我数学活该学不好。

#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int p=1e9+7;
const int N=5e6;
const int M=2e6+5;
const int MOD=9747111;
const int INV2=500000004;
const int INV6=166666668;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
struct node{
    int to,nxt,w;
}e[M];
bool he[N+5];
int su[N+5],tot,cnt,head[MOD+5],phi[N+5],sum[N+5];
inline void add(int v,int w){
    int u=v%MOD;
    e[++cnt].to=v;e[cnt].w=w;e[cnt].nxt=head[u];head[u]=cnt;
}
inline int query(int v){
    int u=v%MOD;
    for(int i=head[u];i;i=e[i].nxt)
        if(v==e[i].to)return e[i].w;
    return -1;
}
inline int sub(int a,int b){
    a-=b;if(a<0)a+=p;if(a>=p)a-=p;return a;
}
inline int inc(int a,int b){
    a+=b;if(a<0)a+=p;if(a>=p)a-=p;return a;
}
inline int s1(int l,int r){
    return (ll)inc(l,r)*sub(r+1,l)%p*INV2%p;
}
inline int s2(int n){
    return (ll)n*(n+1)%p*(2*n+1)%p*INV6%p;
}
void Euler(int n){
    phi[1]=1;
    for(int i=2;i<=n;i++){
        if(!he[i]){
            su[++tot]=i;phi[i]=i-1;
        }
        for(int j=1;j<=tot&&i*su[j]<=n;j++){
            int pri=su[j];he[i*pri]=1;
            if(i%pri==0){
                phi[i*pri]=phi[i]*pri;break;
            }else phi[i*pri]=phi[i]*phi[pri];
        }
    }
    for(int i=1;i<=n;i++)sum[i]=inc(sum[i-1],(ll)phi[i]*i%p);
}
int S(int n){
    if(n<=N)return sum[n];
    int tmp=query(n);
    if(tmp!=-1)return tmp;
    int ans=0;
    for(int i=2,j;i<=n;i=j+1){
        j=n/(n/i);
        ans=inc(ans,(ll)s1(i,j)*S(n/i)%p);
    }
    ans=sub(s2(n),ans);
    add(n,ans);
    return ans;
}
inline int f(int n){
    int ans=0;
    for(int i=1,j;i<=n;i=j+1){
        j=n/(n/i);
        ans=inc(ans,(ll)S(n/i)*(j-i+1)%p);
    }
    ans=(ll)(ans+n)*INV2%p;
    return ans;
}
int main(){
    Euler(N);
    int a=read(),b=read();
    printf("%d\n",sub(f(b),f(a-1)));
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

posted @ 2018-06-09 21:21  luyouqi233  阅读(268)  评论(0编辑  收藏  举报