「51nod1227」平均最小公倍数 题解

本文网址:https://www.cnblogs.com/zsc985246/p/17392004.html ,转载请注明出处。

题目大意

\[A(n)=\frac{1}{n} \sum_{i=1}^{n} \text{lcm}(n,i)\\ F(a,b)=\sum_{i=a}^{b} A(i)\\ \]

给定 \(a,b\),求 \(F(a,b) \bmod 10^9+7\)

\(1 \le a \le b \le 10^9\)

思路

首先我们可以想到,如果我们定义 \(B(n)=\underset{i=1}{\overset{n}{\sum}} A(i)\),那么 \(F(a,b)=B(b)-B(a-1)\)

然后我们开始逐层推式子。

\[A(n)=\frac{1}{n} \sum_{i=1}^{n} \text{lcm}(n,i)\\ \ \ \ \ \ \ \ \ \ =\frac{1}{n} \sum_{i=1}^{n} \frac{n \times i}{\gcd(n,i)}\\ \ \ \ \ =\sum_{i=1}^{n} \frac{i}{\gcd(n,i)} \]

然后代入 \(B(n)\) 中,根据套路枚举因数,将分母上的 \(\gcd\) 拿出来:

\[B(n)=\sum_{i=1}^{n} A(i)\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\ =\sum_{i=1}^{n} \sum_{j=1}^{i} \frac{j}{\gcd(i,j)}\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\ \ =\sum_{i=1}^{n} \sum_{d|i} \sum_{j=1}^{i} \frac{j}{d}[\gcd(i,j)=d]\\ \ \ \ \ \ =\sum_{i=1}^{n} \sum_{d|i} \sum_{j=1}^{i} \frac{j}{d}[\gcd(\frac{i}{d},\frac{j}{d})=1]\\ \ =\sum_{i=1}^{n} \sum_{d|i} \sum_{j=1}^{\frac{i}{d}} j[\gcd(\frac{i}{d},j)=1]\\ \ \ \ \ \ \ \ \ =\sum_{d=1}^{n} \sum_{i=1}^{n} [d|i]\sum_{j=1}^{\frac{i}{d}} j[\gcd(\frac{i}{d},j)=1]\\ =\sum_{d=1}^{n} \sum_{i=1}^{\lfloor\frac{n}{d}\rfloor} \sum_{j=1}^{i} j[\gcd(i,j)=1]\\ \]

然后我们再用莫比乌斯反演把 \(\gcd\) 打开:

\[\sum_{j=1}^{i} j[\gcd(i,j)=1]=\sum_{j=1}^{i} j \sum_{x|\gcd(i,j)} \mu(x)\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =\sum_{x|i} \mu(x) \sum_{j=1}^{i} j[j \bmod x = 0]\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =\sum_{x|i} \mu(x) \sum_{j=1}^{\frac{i}{x}} xj\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =\sum_{x|i} \mu(x) \frac{1}{2}x(1+\frac{i}{x})\frac{i}{x}\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =\frac{i}{2} \sum_{x|i} \mu(x) (1+\frac{i}{x})\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =\frac{i}{2} (\sum_{x|i} \mu(x) + \sum_{x|i} \frac{i}{x}\mu(x))\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =\frac{i}{2} ([i=1]+ \varphi(i))\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =\frac{1}{2} ([i=1]+i\varphi(i)) \]

然后我们把这一坨放回原来的式子:

\[B(n)=\sum_{d=1}^{n} \sum_{i=1}^{\lfloor\frac{n}{d}\rfloor} \sum_{j=1}^{i} j[\gcd(i,j)=1]\\ \ \ \ \ \ =\frac{1}{2} \sum_{d=1}^{n} \sum_{i=1}^{\lfloor\frac{n}{d}\rfloor} [i=1]+i\varphi(i)\\ =\frac{n}{2} + \frac{1}{2} \sum_{d=1}^{n} \sum_{i=1}^{\lfloor\frac{n}{d}\rfloor} i\varphi(i)\\ \]

然后我们设 \(f(i)=i\varphi(i)\),我们可以简单地推导出 \(f\) 是一个积性函数。

对于互质的两个数 \(a,b\)\(f(a)f(b)=ab\varphi(a)\varphi(b)\)

因为 \(\varphi(n)\) 是积性函数,所以 \(\varphi(a)\varphi(b)=\varphi(ab)\)

所以 \(f(a)f(b)=ab\varphi(ab)=f(ab)\)

后面是一个整除分块,所以现在我们需要求的实际上是积性函数 \(f(n)\) 的前缀和,可以想到使用杜教筛:

\[(\text{Id} * f)(i)=\sum_{d|i}f(d) \times \text{Id}(\frac{i}{d})\\ \ \ \ \ \ \ \ \ \ \ \ \ \ =\sum_{d|i}d\varphi(d) \times \frac{i}{d}\\ \ \ \ \ =i\sum_{d|i}\varphi(d)\\ =i^2\ \ \ \ \ \ \ \ \]

代入杜教筛公式中,得到:

\[\text{Id}(1)S(n)=\sum_{i=1}^{n} (\text{Id} * f)(i) - \sum_{i=2}^{n} \text{Id}(i)S(\lfloor\frac{n}{i}\rfloor)\\ S(n)=\sum_{i=1}^{n} i^2 - \sum_{i=2}^{n}iS(\lfloor\frac{n}{i}\rfloor) \]

这样我们就求得了 \(S(n)\)

最后我们利用推出来的公式求解 \(B(n)\) 就好了。

代码实现

求解 \(B(n)\) 的时候不要忘记除以 \(2\)

注意取模。

#include<bits/stdc++.h>
#define ll long long
#define For(i,a,b) for(ll i=(a);i<=(b);++i)
#define Rep(i,a,b) for(ll i=(a);i>=(b);--i)
const ll N=1e6+10;
using namespace std;
const ll mod=1e9+7;

ll phi[N],tot,p[N],vis[N];
void init(ll n){//筛出欧拉函数,然后计算f函数前缀和的前n项
	phi[1]=1;
	For(i,2,n){
		if(!vis[i])p[++tot]=i,phi[i]=i-1;
		For(j,1,tot){
			if(i*p[j]>n)break;
			vis[i*p[j]]=1;
			if(i%p[j]==0){
				phi[i*p[j]]=phi[i]*p[j];
				break;
			}
			phi[i*p[j]]=phi[i]*(p[j]-1);
		}
	}
	For(i,2,n)phi[i]=(phi[i-1]+phi[i]*i%mod)%mod;//计算f函数前缀和
}

map<ll,ll>book;
ll calc(ll n){//求f的前缀和
	if(n<=1e6)return phi[n];//提前计算好的
	if(book[n])return book[n];//记忆化
	//杜教筛
	ll s=n*(2*n+1)%mod*(n+1)%mod*166666668%mod,k;//166666668是6在模1000000007下的逆元
	for(ll i=2;i<=n;i=k+1){//整除分块
		k=n/(n/i);
		s=(s-calc(n/i)*(i+k)%mod*(k-i+1)%mod*500000004%mod)%mod;//500000004是2在模1000000007下的逆元
	}
	return book[n]=s;
}

ll solve(ll n){
	ll res=n,k;
	for(ll i=1;i<=n;i=k+1){//整除分块
		k=n/(n/i);
		res=(res+calc(n/i)*(k-i+1)%mod)%mod;
	}
	return res*500000004%mod;//不要忘了除以2
}

void mian(){
	
	init(1e6);
	ll a,b;
	scanf("%lld%lld",&a,&b);
	printf("%lld",(solve(b)-solve(a-1)+mod)%mod);
	
}

int main(){
	int T=1;
//	scanf("%d",&T);
	while(T--)mian();
	return 0;
}

尾声

如果你发现了问题,你可以直接回复这篇题解

如果你有更好的想法,也可以直接回复!

posted @ 2023-05-11 19:46  zsc985246  阅读(223)  评论(0编辑  收藏  举报