P2568 GCD
题目描述
给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对.
输入输出格式
输入格式:
一个整数N
输出格式:
答案
输入输出样例
输入样例#1:
4
输出样例#1:
4
说明
对于样例((2,2),(2,4),(3,3),(4,2))
(1<=N<=10^7)
来源:bzoj2818
本题数据为洛谷自造数据,使用CYaRon耗时5分钟完成数据制作。
Solution
方法1:莫比乌斯反演,方法和yy的gcd一样
方法2:欧拉函数
题目就是要我们求
[Ans=sum_{pin prime}sum_{i=1}^nsum_{j=1}^n[gcd(i,j)=p]=sum_{pin prime}sum_{i=1}^{frac np}sum_{j=1}^{frac np}[gcd(i,j)=1]
]
那么其实就是欧拉函数的的定义
欧拉函数(phi(i))即为i以内与i互质的数的个数
考虑对于一个质数(p),对于(gcd(a,b)=p)也就是(gcd(x imes p,y imes p)=1),那么对于(1<=a,b<=frac np),一个质数(p)对答案的贡献就是
[sum_{i=1}^{frac np}phi(i)
]
那么线筛求一下欧拉函数顺便求一下前缀和就可以了
注意:因为(4,2),(2,4)这样的数对是算两个的,所以答案要( imes) 2,其次,我们是不会计算一个数本身是质数的情况的,所以还要加上(n)以内质数的个数
(顺便吐槽一句,还是莫比乌斯反演好用,真的难打)
Code
#include<bits/stdc++.h>
#define lol long long
#define il inline
#define rg register
#define Min(a,b) (a)<(b)?(a):(b)
#define Max(a,b) (a)>(b)?(a):(b)
#define NN 10000000
using namespace std;
const int N=1e7+10;
int n,tot;
lol phi[N],prime[N];
bool vis[N];
il void init() {
for(rg int i=2;i<=n;i++) {
if(!vis[i]) prime[++tot]=i,phi[i]=i-1;
for(rg int j=1;j<=tot && 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(rg int i=1;i<=n;i++) phi[i]+=phi[i-1];
}
int main()
{
ios::sync_with_stdio(0);
cin>>n; init(); lol ans=0;
for(rg int i=1;i<=tot;i++) ans+=phi[n/prime[i]]*2;
cout<<ans+tot<<endl;
}