欧拉函数 - GCD(最大公约数) - 洛谷 P2568
给 定 整 数 N , 求 1 ≤ x , y ≤ N 且 G C D ( x , y ) 为 素 数 的 数 对 ( x , y ) 有 多 少 对 。 给定整数N,求1≤x,y≤N且GCD(x,y)为素数的数对(x,y)有多少对。 给定整数N,求1≤x,y≤N且GCD(x,y)为素数的数对(x,y)有多少对。
G C D ( x , y ) 即 求 x , y 的 最 大 公 约 数 。 GCD(x,y)即求x,y的最大公约数。 GCD(x,y)即求x,y的最大公约数。
输入格式
输入一个整数N
输出格式
输出一个整数,表示满足条件的数对数量。
数据范围
1 ≤ N ≤ 1 0 7 1≤N≤10^7 1≤N≤107
输入样例:
4
输出样例:
4
分析:
问题转化:
求 g c d ( x , y ) = P < = > g c d ( x P , y P ) = 1 , 其 中 P 是 质 数 。 求gcd(x,y)=P\quad<=>\quad gcd(\frac{x}{P},\frac{y}{P})=1,其中P是质数。 求gcd(x,y)=P<=>gcd(Px,Py)=1,其中P是质数。
问 题 转 化 为 : 求 1 ≤ x , y ≤ N P 且 G C D ( x , y ) = 1 的 数 对 ( x , y ) 有 多 少 对 。 问题转化为:求1≤x,y≤\frac{N}{P}且GCD(x,y)=1的数对(x,y)有多少对。 问题转化为:求1≤x,y≤PN且GCD(x,y)=1的数对(x,y)有多少对。
求 某 段 区 间 内 , 互 质 的 点 对 的 数 量 , 参 照 : 求某段区间内,互质的点对的数量,参照: 求某段区间内,互质的点对的数量,参照:欧拉函数 - Visible Lattice Points - POJ 3090
所 以 , 我 们 先 预 处 理 出 不 超 过 N 的 所 有 质 数 , 对 于 每 一 个 质 数 P , 都 需 要 计 算 一 遍 ∑ i = 2 N P ϕ ( i ) × 2 + 1 所以,我们先预处理出不超过N的所有质数,对于每一个质数P,都需要计算一遍\sum_{i=2}^{\frac{N}{P}}\phi(i)×2+1 所以,我们先预处理出不超过N的所有质数,对于每一个质数P,都需要计算一遍∑i=2PNϕ(i)×2+1
注 意 : 本 题 需 要 单 独 加 上 y = x 上 的 点 ( 1 , 1 ) 。 注意:本题需要单独加上y=x上的点(1,1)。 注意:本题需要单独加上y=x上的点(1,1)。
由 于 需 要 多 次 查 询 区 间 和 , 故 我 们 另 预 处 理 前 缀 和 数 组 S [ i ] = ∑ j = 1 i ϕ ( j ) , 由于需要多次查询区间和,故我们另预处理前缀和数组S[i]=\sum_{j=1}^i\phi(j), 由于需要多次查询区间和,故我们另预处理前缀和数组S[i]=∑j=1iϕ(j),
注 意 ϕ ( 1 ) = 0 , 因 为 点 ( 1 , 1 ) 是 单 独 处 理 累 加 的 。 注意\phi(1)=0,因为点(1,1)是单独处理累加的。 注意ϕ(1)=0,因为点(1,1)是单独处理累加的。
最 终 答 案 : ∑ i = 1 c n t 2 × S [ N P i ] + 1 , 其 中 c n t 是 N 以 内 质 数 的 总 个 数 , P i 表 示 第 i 个 质 数 。 最终答案:\sum_{i=1}^{cnt}2×S[{\frac{N}{P_i}}]+1,其中cnt是N以内质数的总个数,P_i表示第i个质数。 最终答案:∑i=1cnt2×S[PiN]+1,其中cnt是N以内质数的总个数,Pi表示第i个质数。
代码:
#include<iostream>
#define ll long long
using namespace std;
const int N=1e7+10;
int primes[N],cnt;
bool st[N];
int phi[N];
ll s[N];
void get_prime(int n)
{
for(int i=2;i<=n;i++)
{
if(!st[i])
{
primes[cnt++]=i;
phi[i]=i-1;
}
for(int j=0;primes[j]*i<=n;j++)
{
st[primes[j]*i]=true;
if(i%primes[j]==0)
{
phi[i*primes[j]]=phi[i]*primes[j];
break;
}
phi[i*primes[j]]=phi[i]*(primes[j]-1);
}
}
for(int i=1;i<=n;i++) s[i]=s[i-1]+phi[i];
}
int main()
{
int n;
cin>>n;
get_prime(n);
ll res=0;
for(int i=0;i<cnt;i++)
{
int p=primes[i];
res+=(s[n/p]*2)+1;
}
cout<<res<<endl;
return 0;
}