1. 程式人生 > >BZOJ 2818 GCD 【歐拉函數 || 莫比烏斯反演】

BZOJ 2818 GCD 【歐拉函數 || 莫比烏斯反演】

true names namespace sin () 莫比烏斯反演 lse tps lin

傳送門:https://www.lydsy.com/JudgeOnline/problem.php?id=2818

2818: Gcd

Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 9236 Solved: 4126
[Submit][Status][Discuss]

Description

給定整數N,求1<=x,y<=N且Gcd(x,y)為素數的
數對(x,y)有多少對.

Input

一個整數N

Output

如題

Sample Input

4

Sample Output

4

HINT


對於樣例(2,2),(2,4),(3,3),(4,2)


1<=N<=10^7

解題思路:

老套路:GCD( x, y ) = p 轉換成 GCD( x/p, y/p ) = 1;

那麽按照原來的配方,我們需要枚舉 x/p 或者 y/p 其中一個數,然後另外一個數的總數通過歐拉函數求得。

假設選擇枚舉 y/p ,那麽還需要暴力一遍枚舉素數。(一開始就是直接這樣暴力。。。)

但是其實不需要,O( n ) 內同時篩出素數和歐拉函數值:https://oi.abcdabcd987.com/sieve-prime-in-linear-time/

同時記錄一下歐拉函數前綴和 sum[k] ,根據上面的轉換我們可知:

如果給出 x <= y ,則直接枚舉素數枚舉y,然後歐拉函數求所有方案數即可;

但是這裏沒有明確表明 x 和 y 的大小關系, 但是我們還是只求一半 即 (默認 x <= y)的情況,然後這個答案乘以 2 就是 (y <= x)的情況了,需要去一下重(即 x = y = 1)的情況。

枚舉 素數 p ,求 [ 1, N/p ] 中互質的數對的總數, 即 2*sum[ N/p ] - 1;

AC code:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4 const int MAXN = 1e7+10;
 5 bool com[MAXN];
6 int primes, prime[MAXN], phi[MAXN]; 7 LL sum[MAXN]; 8 9 void get_phi(int n){ 10 phi[1] = 1; 11 for (int i = 2; i <= n; ++i) 12 { 13 if (!com[i]) 14 { 15 prime[primes++] = i; 16 phi[i] = i-1; 17 } 18 for (int j = 0; j < primes && i*prime[j] <= n; ++j) 19 { 20 com[i*prime[j]] = true; 21 if (i % prime[j]) 22 phi[i*prime[j]] = phi[i]*(prime[j]-1); 23 else 24 { phi[i*prime[j]] = phi[i]*prime[j]; break; } 25 } 26 //sum[i] = sum[i-1]+phi[i]; 27 } 28 } 29 int main() 30 { 31 int N; 32 scanf("%d", &N); 33 get_phi(N); 34 sum[1] = 1; 35 for(int i = 2; i <= N/2; i++){ 36 sum[i] = sum[i-1]+phi[i]; 37 // phi[i] = phi[i-1]+phi[i]; 38 } 39 // printf("%d\n", phi[1]); 40 LL ans = 0; 41 for(int i = 0; i < primes; i++){ 42 ans = ans + (sum[N/prime[i]]*2-1); 43 } 44 printf("%lld\n", ans); 45 46 return 0; 47 }

BZOJ 2818 GCD 【歐拉函數 || 莫比烏斯反演】