【bzoj2818】Gcd
2014年6月15日3,0930
Description
给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的
数对(x,y)有多少对.
Input
一个整数N
Output
如题
Sample Input
4
Sample Output
4
HINT
hint
对于样例(2,2),(2,4),(3,3),(4,2)
1<=N<=10^7
思路:
求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对
我们考虑枚举每个素数,那么就变成求Gcd(x/p,y/p)为1的数对(x/p,y/p)有多少对。总会找到一个x使得x%p==0且x < n,相对应得y就应该满足Gcd(x/p,y/p)为1。对于每一个x/p,就有phi(x/p)个y。也就是说每个素数p对于答案的贡献就是(1 ~ n / p) 中有序互质对的个数。
所以有序互质对的个数为(1 ~ n/p)的欧拉函数之和乘2减1(要求的是有序互质对,乘2以后减去(1, 1)多算的一次)。
那么就只需要先筛出欧拉函数再求个前缀和就可以了。
#include <cstdio>
#include <iostream>
#define LL long long
using namespace std;
const int N = 1e7+10;
int primesize, n;
int prime[N], phi[N];
bool isnot[N];
LL sum[N];
void init(){
isnot[1] = 1;
phi[1] = 1;
sum[1] = 1;
for(int i=2; i<=n; i++){
if( !isnot[i] ){
prime[++primesize] = i;
phi[i] = i - 1;
}
for(int t=1; t<=primesize; t++){
int j = prime[t] * i;
if( j > n ) break;//避免崩溃
isnot[j] = 1;
phi[j] = phi[i] * phi[prime[t]];
if(i % prime[t] == 0){
phi[j] = prime[t] * phi[i];
break;
}
}
sum[i] = sum[i-1] + phi[i];
}
}
int main(){
scanf("%d", &n);
LL ans = 0, tot = 0;
init();
for(int i=1; prime[i]<=n && prime[i]; i++){
ans += sum[n/prime[i]];
tot++;
}
ans *= 2;
ans -= tot;//x==y的情况去重
printf("%lld", ans);
return 0;
}