AcWing算法提高课-5.5.2最大公约数

宣传一下 算法提高课整理

CSDN个人主页:更好的阅读体验

原题链接

题目描述

给定整数 N N N,求 1 ≤ x , y ≤ N 1 \le x,y \le N 1≤x,y≤N 且 gcd ⁡ ( x , y ) \gcd(x,y) gcd(x,y) 为素数的数对 ( x , y ) (x,y) (x,y) 有多少对。

输入格式

输入一个整数 N N N。

输出格式

输出一个整数,表示满足条件的数对数量。

数据范围

1 ≤ N ≤ 1 0 7 1 \le N \le 10^7 1≤N≤107

输入样例:

复制代码
4

输出样例:

复制代码
4

思路

首先考虑暴力。

本题答案为:
∑ i = 1 n ∑ j = 1 n ∑ p ∈ P [ gcd ⁡ ( i , j ) = p ] \sum_{i=1}^{n}\sum_{j=1}^{n}\sum_{p \in \mathbb{P}}^{}[\gcd(i,j)=p] i=1∑nj=1∑np∈P∑[gcd(i,j)=p]

把 gcd ⁡ ( i , j ) = p \gcd(i,j)=p gcd(i,j)=p 变成 gcd ⁡ ( i , j ) = 1 \gcd(i,j)=1 gcd(i,j)=1 然后把 p p p 除到前面的 n n n 里。

即: ∑ p ∈ P ∑ i = 1 ⌊ n p ⌋ ∑ j = 1 ⌊ n p ⌋ [ gcd ⁡ ( i , j ) = 1 ] \sum_{p \in \mathbb{P}}^{}\sum_{i=1}^{\lfloor\frac{n}{p}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{p}\rfloor}[\gcd(i,j)=1] p∈P∑i=1∑⌊pn⌋j=1∑⌊pn⌋[gcd(i,j)=1]

5.5.1 可见的点 相同,我们可以将以上代数式变换为:

2 × ∑ p ∈ P ∑ i = 1 ⌊ n p ⌋ φ ( i ) + 1 2 \times\sum_{p \in \mathbb{P}}^{}\sum_{i=1}^{\lfloor\frac{n}{p}\rfloor}\varphi(i)+1 2×p∈P∑i=1∑⌊pn⌋φ(i)+1

这里不再进行推导,读者可以自行点击上方链接进行阅读。

此时进行计算,时间复杂度近似为 O ( n 2 ln ⁡ n ) \large{O(\frac{n^2}{\ln n})} O(lnnn2),将 n = 1 0 7 n=10^7 n=107 代入计算,发现超过 1 0 8 10^8 108,在 1 s 1s 1s 的时限内会 TLE \text{TLE} TLE。

我们看到 ∑ i = 1 n p φ ( n p ) \large\sum_{i=1}^{\frac{n}{p}}\varphi(\frac{n}{p}) ∑i=1pnφ(pn) 可以考虑预处理欧拉函数前缀和。

假设 s k = ∑ i = 1 k φ ( i ) \large{s_k=\sum_{i=1}^{k}\varphi(i)} sk=∑i=1kφ(i),则原式可化为:

2 × ∑ p ∈ P s ⌊ n p ⌋ + 1 \large{2 \times\sum_{p \in \mathbb{P}}^{}s_{\lfloor\frac{n}{p}\rfloor}+1} 2×p∈P∑s⌊pn⌋+1

此时我们枚举 n n n 的所有质因数进行计算就不会超时。

算法时间复杂度

预处理 φ ( i ) \varphi(i) φ(i): O ( n ) O(n) O(n);

预处理 s i s_i si: O ( n ) O(n) O(n);

计算结果: O ( n ln ⁡ n ) \large{O(\frac{n}{\ln n})} O(lnnn)。

因此最高时间复杂度: O ( n ) O(n) O(n),可以过。

注意: 数论题目中,开 long long 已经是常识,所以很有必要写一条 #define int long long 避免犯错。

AC Code

C + + \text{C}++ C++

cpp 复制代码
#include <iostream>
#define int long long

using namespace std;

const int N = 1e7 + 10;

int n;
int primes[N], cnt;
int euler[N], s[N];
bool st[N];

void get_eulers(int n)
{
    euler[1] = 1;
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i])
        {
            primes[cnt ++ ] = i;
            euler[i] = i - 1;
        }
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            int t = primes[j] * i;
            st[t] = true;
            if (i % primes[j] == 0)
            {
                euler[t] = euler[i] * primes[j];
                break;
            }
            euler[t] = euler[i] * (primes[j] - 1);
        }
    }
}

main()
{
    scanf("%lld", &n);
    get_eulers(n); // 线性筛质数和欧拉函数

    for (int i = 1; i <= n; i ++ ) // 预处理欧拉函数前缀和
        s[i] = s[i - 1] + euler[i];

    int res = 0;
    for (int i = 0; i < cnt; i ++ ) // 枚举 n 以内的质数
        res += 2 * s[n / primes[i]] - 1;

    printf("%lld\n", res);
    return 0;
}

最后,如果觉得对您有帮助的话,点个赞再走吧!

相关推荐
superior tigre3 分钟前
22 括号生成
算法·深度优先
君义_noip1 小时前
信息学奥赛一本通 1952:【10NOIP普及组】三国游戏 | 洛谷 P1199 [NOIP 2010 普及组] 三国游戏
c++·信息学奥赛·csp-s
努力也学不会java1 小时前
【缓存算法】一篇文章带你彻底搞懂面试高频题LRU/LFU
java·数据结构·人工智能·算法·缓存·面试
旖-旎1 小时前
二分查找(x的平方根)(4)
c++·算法·二分查找·力扣·双指针
ECT-OS-JiuHuaShan2 小时前
朱梁万有递归元定理,重构《易经》
算法·重构
顶点多余2 小时前
使用C/C++语言链接Mysql详解
数据库·c++·mysql
汉克老师2 小时前
GESP2026年3月认证C++四级( 第二部分判断题(1-10))
c++·指针·函数重载·文件操作·数组·gesp4级·gesp四级
智者知已应修善业2 小时前
【51单片机独立按键控制数码管移动反向,2片74CH573/74CH273段和位,按键按下保持原状态】2023-3-25
经验分享·笔记·单片机·嵌入式硬件·算法·51单片机
khddvbe2 小时前
C++并发编程中的死锁避免
开发语言·c++·算法
C羊驼3 小时前
C语言:两天打鱼,三天晒网
c语言·经验分享·笔记·算法·青少年编程