洛谷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

猜你喜欢

转载自www.cnblogs.com/Lubixiaosi-Zhaocao/p/9932682.html