1. 程式人生 > >洛谷P2568 GCD(線性篩法)

洛谷P2568 GCD(線性篩法)

題目連結:傳送門

題目:

題目描述

給定整數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, sizeof
prime); 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; }
View Code