标签:code gcd name register int mat solution namespace 莫比乌斯反演
给定\(n\),求\(1<=x,y<=n\)满足\(gcd(x,y)=p\)(其中\(p\)为质数)的\((x,y)\)有多少对
乍一看是莫比乌斯反演,虽然我不会莫比乌斯反演
其实这道题是简单的筛法+欧拉函数
\(ans=\sum\limits_{i=1}^n\sum\limits_{j=1}^n[gcd(i,j)==p]\)
\(gcd\)常用技巧
\(=\sum\limits_{p\in prime}\sum\limits_{i=1}^{\lfloor \frac{n}{p} \rfloor}\sum\limits_{j=1}^{\lfloor \frac{n}{p} \rfloor}[gcd(i,j)==1]\)
因为\(i,j\)是等效的,所以只用将\(j\)枚举到\(i\)即可,保证\(j<i\)再乘\(2\),注意只有\(i=1,j=1\)(\(i,j\)矩阵对角线上)被算两次且符合\(gcd==1\),所以再枚举完\(i\)之后要\(-1\),注意\(-1\)是在外层。
\(=\sum\limits_{p\in prime}2\sum\limits_{i=1}^{\lfloor \frac{n}{p} \rfloor}\sum\limits_{j=1}^{i}[gcd(i,j)==1]\ -1\)
我们发现里面实际就是欧拉函数
\(=\sum\limits_{p\in prime}2\sum\limits_{i=1}^{\lfloor \frac{n}{p} \rfloor}\phi(i)\ -1\)
线性筛+枚举即可
还是好好记一下线性筛计算欧拉函数的几个公式
#include<cstdio>
#include<iostream>
#include<cstring>
#define maxn 10000010
#define re register
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
ll ans;
int n,is_not_prime[maxn],prime[maxn],pcnt,phi[maxn];
void pre()
{
is_not_prime[1]=1;
phi[1]=1;
for(int i=1;i<=n;++i)
{
if(!is_not_prime[i])
{
prime[++pcnt]=i;
phi[i]=i-1;
}
for(int j=1;j<=pcnt;++j)
{
if(i*prime[j]>n) break;
is_not_prime[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] * phi[prime[j]];
}
}
}
int main()
{
n=read();
pre();
for(re int i=1;i<=pcnt;++i)
{
for(re int j=1;j<=n/prime[i];++j)
{
ans+=2*phi[j];
}
ans--;
}
//for(re int i=1;i<=n;++i) printf("%d ",phi[i]);
printf("%lld\n",ans);
return 0;
}
标签:code gcd name register int mat solution namespace 莫比乌斯反演
原文地址:https://www.cnblogs.com/Liuz8848/p/11469593.html