P2568 GCD

原题传送门

题目大意:给定正整数\(n\),求\(1\le x,y\le n\)\(\gcd(x,y)\)为素数的数对\((x,y)\)有多少对。

思路:把题意写成柿子即 :\(\sum_{p\in prime}\sum_{i=1}^n\sum_{j=1}^n[gcd(i,j)=p]\)

\(gcd\)进行套路变形 : \(\sum_{p\in prime}\sum_{i=1}^{\lfloor\frac{n}{p}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{p}\rfloor}[gcd(i,j)=1]\)

接下来改变\(j\)的枚举上界,由于\(x=y=1\)这种情况被多算了一次,所以要\(-1\),柿子变形为 :
\(\sum_{p\in prime}(2*\sum_{i=1}^{\lfloor\frac{n}{p}\rfloor}(\sum_{j=1}^{i}[gcd(i,j)=1])-1)\)

对于\(i\),小于或等于\(i\)与其互质的正整数数目,即为欧拉函数\(\varphi(i)\) :\(\sum_{j=1}^{i}[gcd(i,j)=1]=\varphi(i)\)

故柿子最终化简为:\(\sum_{p\in prime}(2*\sum_{i=1}^{\lfloor\frac{n}{p}\rfloor}\varphi(i)-1)\)

由于是单组查询,我们只需要要预处理\(\varphi(x)\)及其前缀和即可

复杂度\(O(n)\)

#include <bits/stdc++.h>
using namespace std;
const int N=1e7+10,mod=1e9+7;
typedef long long ll;
int cnt,prime[N],phi[N],vis[N],n;
ll sum[N];
void get_phi(int n){
	phi[1]=1;
	for(int i=2;i<=n;i++){
		if(!vis[i]){
			prime[++cnt]=i;
			phi[i]=i-1;
		}
		for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
			vis[i*prime[j]]=1;
			if(i%prime[j]==0){
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
			else phi[i*prime[j]]=phi[i]*(prime[j]-1);
		}
	}
	for(int i=1;i<=n;i++) sum[i]=sum[i-1]+phi[i];
}
int main(){
	cin>>n;
	get_phi(n);
	ll ans=0;
	for(int i=1;i<=cnt;i++) ans+=2*sum[n/prime[i]]-1;
	cout<<ans<<endl;
	return 0;
}
 
posted @ 2021-12-14 16:43  Wraith-Fiee  阅读(16)  评论(0)    收藏  举报