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

题目

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

\(\sum_{i=l}^rA(i)\)\(n\leq 10^9\)


分析

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

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

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

\[\sum_{i=1}^n\sum_{d|i}\sum_{j=1}^{\frac{i}{d}}j[\gcd(\frac{i}{d},j)==1]=\sum_{i=1}^n\sum_{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)=\begin{cases}\frac{n\varphi(n)}{2}[n>1]\\1\end{cases}\)

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

枚举 \(d\) 可以得到

\[\frac{n}{2}+\frac{1}{2}\sum_{d=1}^nd\varphi(d)\lfloor\frac{n}{d}\rfloor \]

外层整除分块,然后里层卷一个 \(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)));
}
posted @ 2021-11-05 20:11  lemondinosaur  阅读(21)  评论(0编辑  收藏  举报