題目描述
給定整數N,求1<=x,y<=N且Gcd(x,y)爲素數的數對(x,y)有多少對?
輸入
一個整數
1<=N<=1000000
輸出
一個整數
樣例輸入
4
樣例輸出
4
提示
【樣例解釋】
(2,2),(2,4),(3,3),(4,2)
思路
(本文所有的P,均表示質數)
對於x,y 1 <= x,y <= n,且gcd(x,y) = P
由此,我們很容易相當歐拉篩法(Euler)
:是小於n的正整數中與n互質的數的數目((1) )
註明:源自百度
我們假設gcd(,) ,則一定有 gcd( P, P) P
我們不妨設 <= ,則我們可以得出 <= <= <=
所以我們可以先花( )的時間算出
然後我們只需要將 1 - ()以內的所有值乘二減一後加起來即可,(這些數同時乘以P後,不就是gcd( P, P) P了嗎)
數學表達:
乘二是因爲我們假設的是 <= 的情況,然而實際上,將,的值對調又可以對答案做出貢獻,可是我們還需要減去一個一,這是因爲(1 P,1 P)= P顯然只有一組,所以我們需要減去一個一
總而言之,這裏可用前綴和思想,但是好像空間過不去……
看看代碼有利於理解
#include<cstdio>
#define LL long long
#define reg register
#define M 10000000
int n,tot;
LL ans;
int phi[M + 5],prime[M + 5];
bool vis[M + 5];
void Euler(int N){
phi[1] = 1;
for (reg int i = 2;i <= N; ++ i){
if ( ! vis[i]){
prime[ ++ tot] = i;
phi[i] = i - 1;
}
for (reg int j = 1;j <= tot; ++ j){
if (prime[j] * i > N)
break;
vis[prime[j] * i] = true;
if (i % prime[j] == 0){
phi[i * prime[j]] = prime[j] * phi[i];
break;
} else
phi[i * prime[j]] = (prime[j] - 1) * phi[i];
}
}
}
int main(){
scanf("%d",&n);
Euler(n);
for (reg int i = 1;i <= tot; ++ i){
int g = n / prime[i];
LL sum = 0;
for (reg int j = 1;j <= g; ++ j)
sum += 1ll * phi[j];
ans += (sum * 2 - 1);
}
printf("%lld\n",ans);
return 0;
}