洛谷P2568 GCD(線性篩法)
阿新 • • 發佈:2018-11-08
題目連結:傳送門
題目:
題目描述 給定整數N,求1<=x,y<=N且Gcd(x,y)為素數的數對(x,y)有多少對. 輸入輸出格式 輸入格式: 一個整數N 輸出格式: 答案 輸入輸出樣例 輸入樣例#1: 複製 4 輸出樣例#1: 複製 4 說明 對於樣例(2,2),(2,4),(3,3),(4,2) 1<=N<=10^7 來源:bzoj2818 本題資料為洛谷自造資料,使用CYaRon耗時5分鐘完成資料製作。View Code
看了好幾天數論了,忍不住出來切切水題。
思路:
若已知x,y,因為gcd(x, y)為素數,令p = gcd(x, y),a = x/p,b = y/p,則gcd(a, b) = 1;
所以對於給定的素數p,只要a,b滿足gcd(a, b) = 1,則對應的x = a*p,y = b*p就是滿足題意的一個數對。因為gcd(a, b) = 1,考慮尤拉函式。
不妨令a ≤ b,則對於一個確定的b,a的選擇數有φ(b)種,那麼所有a,b的選擇就有$\sum \phi (b)$種,b*p ≤ N,所以b的上界為N/p。a,b可以互換位置所以要×2,a,b相等時(a = b = 1)只能算一種所以要-1,所以答案為$\sum_{prime\leqslant N}\left ( 2*\sum_{j=1}^{N/prime}\phi (j)-1 \right )$。
線性篩出質數和尤拉函式O(N),列舉所有小於N的素數就可以了O(N/logN)。
總複雜度O(N+N/logN)。
注意:1e7的陣列開多了會MLE,而最小的質數為2,所以尤拉函式和字首和可以只開到N/2的大小。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int MAX_N = 1e7 + 5; int N; int prime[MAX_N+1]; int phi[MAX_N/2+1]; ll sum[MAX_N/2+1]; void getPrime_and_Phi() { memset(prime, 0, sizeofView Codeprime); phi[1] = 1; for (int i = 2; i <= MAX_N; i++) { if (!prime[i]) prime[++prime[0]] = i, phi[i] = i-1; for (int j = 1; j <= prime[0] && prime[j] <= MAX_N/i; j++) { prime[prime[j]*i] = 1; if (prime[j]*i <= MAX_N/2) phi[prime[j]*i] = phi[i] * (i%prime[j] ? prime[j]-1 : prime[j]); if (i % prime[j] == 0) break; } } } void init() { getPrime_and_Phi(); sum[0] = 0; for (int i = 1; i <= MAX_N/2; i++) { sum[i] = sum[i-1] + phi[i]; } } int main() { init(); cin >> N; ll ans = 0; for (int i = 1; i <= prime[0] && prime[i] <= N; i++) { ans += sum[N/prime[i]]*2-1; } cout << ans << endl; return 0; }