[BZOJ 2818] Gcd 线性筛+欧拉函数前缀和
2017-10-01 15:47
211 查看
题目传送门:【BZOJ 2818】
题目大意:输入整数 N,求 1 ≤ x , y ≤ N 且 gcd ( x , y ) 为质数的数对 ( x , y ) 的数目。其中 1 ≤ N ≤ 107。
题目分析:
由题,欲求 gcd ( x , y ) = p(1 ≤ x , y ≤ N,p 为质数),根据 gcd 的性质,
我们可将其转化一下,变成:求 gcd ( x , y ) = 1(1 ≤ x , y ≤ ⌊Np⌋)。
令 ⌊Np⌋ = d,设此时的答案为 anspi;在 1 ≤ x , y ≤ ⌊Np⌋ 这个范围内,根据欧拉函数 φ 的定义(与这个数互质的数的数量),可知:ansd = 2 * ( φ(d) + φ(d-1) + φ(d-2) + …… + φ(2) + φ(1) ) - 1。
对于上式,由于在数对 ( x , y ) 中,x 和 y 可以交换,因此答案要乘以 2;又因为对于 ( 1 , 1 ) 只有一种情况,所以最后的答案要减 1。
之后,我们对每个不大于 N 的质数进行类似的处理,最后得到的答案 ans = ∑anspi(所有的 pi 不大于 N)。
因此,我们只需要预处理出 107以内的所有质数,所有数的 φ 值,以及 φ 值的前缀和,枚举每个质数 pi 并求出对应的 anspi,最后求和即可(前缀和&最后的答案要开 long long)。
下面附上代码:
[cpp] view plain copy print?#include<cstdio>
const int MX=10000005;
int n,ptot=0,prime[MX],phi[MX]; //ptot:质数总数
bool isnot[MX];
long long ans=0,sum_phi[MX]; //sum_phi: φ的前缀和
void sieve(int n){
isnot[1]=true;
phi[1]=1;
for (register int i=2;i<=n;i++){
if (!isnot[i]){
prime[++ptot]=i;
phi[i]=i-1;
}
for (int t=1;t<=ptot;t++){
int j=prime[t]*i;
if (j>n) break;
isnot[j]=true;
phi[j]=phi[prime[t]]*phi[i];
if (i%prime[t]==0){
phi[j]=prime[t]*phi[i];
break;
}
}
}
}
int main(){
scanf(”%d”,&n);
sieve(n);
for (register int i=1;i<=n;i++) //预处理 φ的前缀和
sum_phi[i]=sum_phi[i-1]+phi[i];
for (register int i=1;i<=ptot;i++){ //枚举每个质数 pi并求出此时的 ans
int d=n/prime[i];
ans+=sum_phi[d]*2-1;
}
printf(”%lld”,ans);
return 0;
}
题目大意:输入整数 N,求 1 ≤ x , y ≤ N 且 gcd ( x , y ) 为质数的数对 ( x , y ) 的数目。其中 1 ≤ N ≤ 107。
题目分析:
由题,欲求 gcd ( x , y ) = p(1 ≤ x , y ≤ N,p 为质数),根据 gcd 的性质,
我们可将其转化一下,变成:求 gcd ( x , y ) = 1(1 ≤ x , y ≤ ⌊Np⌋)。
令 ⌊Np⌋ = d,设此时的答案为 anspi;在 1 ≤ x , y ≤ ⌊Np⌋ 这个范围内,根据欧拉函数 φ 的定义(与这个数互质的数的数量),可知:ansd = 2 * ( φ(d) + φ(d-1) + φ(d-2) + …… + φ(2) + φ(1) ) - 1。
对于上式,由于在数对 ( x , y ) 中,x 和 y 可以交换,因此答案要乘以 2;又因为对于 ( 1 , 1 ) 只有一种情况,所以最后的答案要减 1。
之后,我们对每个不大于 N 的质数进行类似的处理,最后得到的答案 ans = ∑anspi(所有的 pi 不大于 N)。
因此,我们只需要预处理出 107以内的所有质数,所有数的 φ 值,以及 φ 值的前缀和,枚举每个质数 pi 并求出对应的 anspi,最后求和即可(前缀和&最后的答案要开 long long)。
下面附上代码:
[cpp] view plain copy print?#include<cstdio>
const int MX=10000005;
int n,ptot=0,prime[MX],phi[MX]; //ptot:质数总数
bool isnot[MX];
long long ans=0,sum_phi[MX]; //sum_phi: φ的前缀和
void sieve(int n){
isnot[1]=true;
phi[1]=1;
for (register int i=2;i<=n;i++){
if (!isnot[i]){
prime[++ptot]=i;
phi[i]=i-1;
}
for (int t=1;t<=ptot;t++){
int j=prime[t]*i;
if (j>n) break;
isnot[j]=true;
phi[j]=phi[prime[t]]*phi[i];
if (i%prime[t]==0){
phi[j]=prime[t]*phi[i];
break;
}
}
}
}
int main(){
scanf(”%d”,&n);
sieve(n);
for (register int i=1;i<=n;i++) //预处理 φ的前缀和
sum_phi[i]=sum_phi[i-1]+phi[i];
for (register int i=1;i<=ptot;i++){ //枚举每个质数 pi并求出此时的 ans
int d=n/prime[i];
ans+=sum_phi[d]*2-1;
}
printf(”%lld”,ans);
return 0;
}
相关文章推荐
- 【欧拉函数+线性筛】bzoj2818: Gcd
- bzoj 2818 gcd 线性欧拉函数
- Bzoj 2818: Gcd 莫比乌斯,分块,欧拉函数,线性筛
- [BZOJ2818] Gcd (数论,欧拉函数,线性筛)
- bzoj2818 Gcd(欧拉函数前缀和)
- BZOJ 2818: Gcd [欧拉函数 质数 线性筛]【学习笔记】
- bzoj2818 gcd 欧拉函数(前缀和)
- bzoj 2818: Gcd 线性筛求欧拉函数
- BZOJ2818: Gcd 欧拉函数求前缀和
- _bzoj2818 Gcd【线性筛法 欧拉函数】
- 【BZOJ】2818 Gcd 欧拉函数
- 【bzoj2818】Gcd 欧拉函数
- BZOJ 2818 GCD(欧拉函数)
- BZOJ 2818 Gcd 线性欧拉筛(Eratosthenes筛)
- bzoj2818: Gcd(欧拉函数)
- bzoj 2818 Gcd 【欧拉函数】
- BZOJ 2818 Gcd 线性欧拉
- BZOJ 2818 GCD【欧拉函数】
- BZOJ 2818 Gcd 线性欧拉
- 【bzoj2818】Gcd 线性筛法