利用差分,我们要求的实际上是这个玩意:
A n s = ∑ n = 1 N ∑ i = 1 n l c m ( i , n ) n Ans=\sum_{n=1}^{N}\frac{\sum\limits_{i=1}^{n}lcm(i,n)}{n} Ans=n=1∑Nni=1∑nlcm(i,n)
根据LCMSUM的推导我们知道:
∑ i = 1 n l c m ( i , n ) = n 2 + n 2 ∑ d ∣ n d ϕ ( d ) \sum_{i=1}^nlcm(i,n)=\frac{n}{2}+\frac{n}{2}\sum_{d\mid n}d\phi(d) i=1∑nlcm(i,n)=2n+2nd∣n∑dϕ(d)
所以这里我们知道:
A n s = ∑ n = 1 N ( 1 2 + 1 2 ∑ d ∣ n d ϕ ( d ) ) = N 2 + 1 2 ∑ n = 1 N ∑ d ∣ n d ϕ ( d ) = N 2 + 1 2 ∑ n = 1 N ∑ d = 1 ⌊ N n ⌋ d ϕ ( d ) \begin{aligned} Ans&=&&\sum_{n=1}^N(\frac{1}{2}+\frac{1}{2}\sum_{d\mid n}d\phi (d))\\ &=&&\frac{N}{2}+\frac{1}{2}\sum_{n=1}^N\sum_{d\mid n}d\phi(d)\\ &=&&\frac{N}{2}+\frac{1}{2}\sum_{n=1}^N\sum_{d=1}^{\lfloor\frac{N}{n}\rfloor}d\phi(d) \end{aligned} Ans===n=1∑N(21+21d∣n∑dϕ(d))2N+21n=1∑Nd∣n∑dϕ(d)2N+21n=1∑Nd=1∑⌊nN⌋dϕ(d)
都是很套路的转换。
构造 f = I d ⋅ ϕ , g = I d f=Id\cdot \phi,g=Id f=Id⋅ϕ,g=Id,就可以直接杜教筛求出 f f f的前缀和了。
代码:
#include
#define ll long long
#define re register
#define cs const
using std::cerr;
using std::cout;
cs int mod=1e9+7;
inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline void Inc(int &a,int b){(a+=b)>=mod&&(a-=mod);}
inline void Dec(int &a,int b){(a-=b)<0&&(a+=mod);}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
cs int inv2=mod+1>>1,inv3=(mod+1)/3,inv6=mul(inv2,inv3);
int l,r;
cs int P=1e6+6,lim=P-6;
int prime[P],pcnt;
bool mark[P];
int f[P];
inline void linear_sieves(){
f[1]=1;
for(int re i=2;i<=lim;++i){
if(!mark[i])prime[++pcnt]=i,f[i]=i-1;
for(int re j=1;i*prime[j]<=lim;++j){
mark[i*prime[j]]=true;
if(i%prime[j]){f[i*prime[j]]=f[i]*(prime[j]-1);}
else {f[i*prime[j]]=f[i]*prime[j];break;}
}
}
for(int re i=1;i<=lim;++i)f[i]=add(f[i-1],mul(f[i],i));
}
struct Map{
static cs int magic=1898599;
int val[magic];
int key[magic];
Map(){memset(key,-1,sizeof key);}
cs int &operator[](cs int &k)cs{
int h=k%magic;
while((~key[h])&&(key[h]^k))h=(h+1)%magic;
return val[h];
}
int &operator[](cs int &k){
int h=k%magic;
while((~key[h])&&(key[h]^k))h=(h+1)%magic;
if((key[h]^k)){key[h]=k;}
return val[h];
}
bool find(cs int &k){
int h=k%magic;
while((~key[h])&&(key[h]^k))h=(h+1)%magic;
return key[h]==k;
}
}sumf;
inline int Sum1(int n){return mul(mul(n,n+1),inv2);}
inline int Sum2(int n){return mul(mul(mul(n,n+1),add(n,n)+1),inv6);}
inline int F(int n){
if(n<=lim)return f[n];
if(sumf.find(n))return sumf[n];
int ans=Sum2(n);
for(int re i=2,j;i<=n;i=j+1){
j=n/(n/i);
Dec(ans,mul(dec(Sum1(j),Sum1(i-1)),F(n/i)));
}
return sumf[n]=ans;
}
inline int calc(int n){
int ans=0;
for(int re i=1,j;i<=n;i=j+1){
j=n/(n/i);
Inc(ans,mul(j-i+1,F(n/i)));
}
return mul(n+ans,inv2);
}
signed main(){
scanf("%d%d",&l,&r);
linear_sieves();
cout<<dec(calc(r),calc(l-1));
return 0;
}