#杜教筛,欧拉函数#51nod 1227 平均最小公倍数

题目

(large A(n)=frac{1}{n}sum_{i=1}^n lcm(i,n))

(sum_{i=l}^rA(i))(nleq 10^9)


分析

题意可以转化成求 (large sum_{i=1}^nfrac{1}{i}sum_{j=1}^i lcm(i,j))

首先把 (lcm) 弄掉就是 (large sum_{i=1}^nsum_{j=1}^ifrac{j}{gcd(i,j)})

考虑枚举 (gcd(i,j)) 那么再化简一下可以得到

[sum_{i=1}^nsum_{d|i}sum_{j=1}^{frac{i}{d}}j[gcd(frac{i}{d},j)==1]=sum_{i=1}^nsum_{d|i}sum_{j=1}^{d}j[gcd(d,j)==1] ]

(large f(n)=sum_{i=1}^{n}j[gcd(n,i)==1]),那么 (large f(n)=egin{cases}frac{nvarphi(n)}{2}[n>1]\1end{cases})

那么原式进一步化简为 (large frac{n}{2}+frac{1}{2}sum_{i=1}^nsum_{d|i}dvarphi(d))

枚举 (d) 可以得到

[frac{n}{2}+frac{1}{2}sum_{d=1}^ndvarphi(d)lfloorfrac{n}{d} floor ]

外层整除分块,然后里层卷一个 (id) 杜教筛就可以了


代码

#include <cstdio>
#include <unordered_map>
using namespace std;
const int N=10000011,mod=1000000007;
const long long i2=(mod+1)/2,i6=i2/3;
int f[N],prime[N],v[N],Cnt,A,B;
unordered_map<int,int>F;
int mo(int x,int y){return x+y>=mod?x+y-mod:x+y;} 
void Pro(int n){
	f[1]=v[1]=1;
	for (int i=2;i<=n;++i){
		if (!v[i]) prime[++Cnt]=v[i]=i,f[i]=i*(i-1ll)%mod;
		for (int j=1;j<=Cnt&&prime[j]<=n/i;++j){
			f[i*prime[j]]=1ll*f[i]*f[prime[j]]%mod,v[i*prime[j]]=1;
			if (i%prime[j]==0){
				f[i*prime[j]]=mo(f[i*prime[j]],1ll*f[i]*prime[j]%mod);
				break;
			}
		}
	}
	for (int i=2;i<=n;++i) f[i]=mo(f[i],f[i-1]);
}
int phid(int n){
	if (n<=N-11) return f[n];
	if (F.find(n)!=F.end()) return F[n];
	int ans=i6*n%mod*(n+1)%mod*(n<<1|1)%mod;
	for (int l=2,r;l<=n;l=r+1)
		r=n/(n/l),ans=mo(ans,mod-i2*(l+r)%mod*(r-l+1)%mod*phid(n/l)%mod);
	return ans;
}
int answ(int n){
	int ans=n,las=0;
	for (int l=1,r,now;l<=n;l=r+1,las=now){
		r=n/(n/l),now=phid(r);
		ans=mo(ans,1ll*(now-las+mod)*(n/l)%mod);
	}
	return i2*ans%mod;
}
int main(){
	Pro(N-11),scanf("%d%d",&A,&B);
	return !printf("%d",mo(answ(B),mod-answ(A-1)));
}
原文地址:https://www.cnblogs.com/Spare-No-Effort/p/15515045.html