前言
数论大法好,人间真善美。。。
题目描述
给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对?
输入
一个整数
1<=N<=1000000
输出
一个整数
样例输入
4
样例输出
4
提示
【样例解释】
(2,2),(2,4),(3,3),(4,2)
思路
拿到这道题很容易想到暴搜,但数据范围很大,所以就要用欧拉函数(不懂的点一下),那又该怎样用欧拉函数来做呢,求的是 gcd(x,y) 为质数的个数,那就是说 x 和 y 除以这个质数就互质了,就只需要枚举 n 以内的质数就行了。
如果已知一质数 k , 则就是求 n/k 以内的互质数。
如果 ( x , y ) 互质,那么 ( y , x ) 也互质 ,所以答案需要乘 2 ,但会有 x = y 的情况,会多计算一次,所以要减去 1 。直接枚举在求欧拉函数会超时,就需要用欧式筛法,边求质数边求其欧拉函数。
代码
结合代码消化理解!
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define ll long long
using namespace std;
int n , pr[10000007] , cnt ;
bool vis[10000007] ;
ll ans , ph[10000007] ;
int main() {
ph[1] = 1 ;
scanf("%d", &n );
for(int i = 2 ; i <= n ; ++ i ) {//欧式筛法
if(!vis[i]) {
cnt ++ ;
pr[cnt] = i ;
ph[i] = i - 1 ;
}
for(int j = 1 ; j <= cnt && i * pr[j] <= n ; ++ j ) {
vis[ i * pr[j] ] = 1 ;
if( i % pr[j] == 0 ) {
ph[ pr[j] * i ] = ph[i] * pr[j] ;
break;
} else
ph [ pr[j] * i] = ph[i] * (pr[j]-1);
}
}
for(int i = 1; i <= n ; ++ i )
ph[i] = ph[i] + ph[i-1];//前缀和,表示 i+1 以内互质数的个数
for(int i = 1 ; i <= cnt ; ++ i )
ans += ph[n/pr[i]]*2-1;
printf("%lld", ans );
return 0;
}