返回顶部

欧拉反演

欧拉反演

\(\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\gcd(i,j)\) .

欧拉函数性质:

\(\sum\limits_{d|n}\varphi(d) = n\)

优化和式技巧:
\(\sum\limits_{i=1}^n\sum\limits_{d|i}x=\sum\limits_{d=1}^n[\frac{n}{d}]x\)

有了以上两个东西,那么:

\(\begin{aligned} &\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\gcd(i,j)\\&= \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{d|\gcd(i,j)}\varphi(d) \\&=\sum_{i=1}^n\sum_{j=1}^n\sum_{d|i}\sum_{d|j}\varphi(d)\\&=\sum_{d=1}^n\varphi(d)*[n/d][n/d]\\&=\sum_{d=1}^n\varphi(d)[\frac{n}{d}]^2\end{aligned}\)

筛一下 \(\varphi(d)\) 求前缀和 \(O(n)\),然后整出分块 $O(\sqrt n) $ 就完成了

#include<bits/stdc++.h>
#define int long long //不开long long 真的会死的
using namespace std;
const int maxn=1e5+7;
bool  vis[maxn]; int cnt,prim[maxn],phi[maxn],n,ans;
void init()
{
	phi[1]=1;
	for(int i = 2; i <= maxn; ++i) {
		if(!vis[i]) {
			prim[++cnt] = i; phi[i] = i - 1;
		}
		for(int j = 1; j <= cnt && prim[j] * i <= maxn; ++j) {
			vis[prim[j] * i] = 1;
			if(i%prim[j]==0) {
				phi[prim[j] * i] = phi[i] * prim[j]; break;
			}
			phi[prim[j] * i] = phi[i] * phi[prim[j]];
		}
	}
	for(int i=2;i<=maxn;++i) phi[i] += phi[i-1];
	
}

signed main() {
	init();
	cin>>n;
	for(int l=1,r;l<=n;l=r+1) {
		int t = n / l;
		r = n / t;
		ans += (phi[r]-phi[l-1]) * t * t;
	}
	cout<<ans;
	
	return 0;
}
posted @ 2022-06-29 21:15  魔幻世界魔幻人生  阅读(45)  评论(0)    收藏  举报