[51nod1238]最小公倍数之和

来源:互联网 发布:单片机论坛网430 编辑:程序博客网 时间:2024/05/22 06:50

题目大意

出一个数N,输出小于等于N的所有数,两两之间的最小公倍数之和。

题解

太懒了
这里写的很好

#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;typedef long long ll;const int maxn=10000000+10,maxha=10000000,mo=1000000007,inv2=(mo+1)/2,inv6=(mo+1)/6;int phi[maxn],pri[maxn],g[maxn];bool bz[maxn];int gg[maxn];ll k,l,t,top,ans;ll i,j,n,m;void prepare(){    ll i,j;    phi[1]=1;    fo(i,2,maxn-10){        if (!bz[i]) pri[++top]=i,phi[i]=i-1;        fo(j,1,top){            if ((ll)i*pri[j]>maxn-10) break;            bz[i*pri[j]]=1;            if (i%pri[j]==0){                phi[i*pri[j]]=phi[i]*pri[j];                break;            }            phi[i*pri[j]]=phi[i]*(pri[j]-1);        }    }    fo(i,1,maxn-10) g[i]=(g[i-1]+(ll)phi[i]*i%mo*i%mo)%mo;}ll getsum(ll r){    r%=mo;    return (ll)r*(r+1)%mo*((2*r+1)%mo)%mo*inv6%mo;}ll calcg(ll n){    if (n<=maxn-10) return g[n];    ll i,j,k;    ll t;    ll l=m/n,r=n%mo;    if (gg[l]) return gg[l];    t=(ll)r*(r+1)%mo*inv2%mo;    t=(ll)t*t%mo;    i=2;    while (i<=n){        j=n/(n/i);        (t-=(ll)(getsum(j)-getsum(i-1))*calcg(n/i)%mo)%=mo;        (t+=mo)%=mo;        i=j+1;    }    return gg[l]=t;}int main(){    prepare();    i=1;    scanf("%lld",&n);    m=n;    while (i<=n){        j=n/(n/i);        ans=(ans+(ll)((i+j)%mo)*(j-i+1)%mo*inv2%mo*calcg(n/i)%mo)%mo;        i=j+1;    }    (ans+=mo)%=mo;    printf("%d\n",ans);}
0 0