C++算法之旅、08 基础篇 | 质数、约数

c++,算法,基础,质数,约数 · 浏览次数 : 1

小编点评

```cpp #include <algorithm>#include <iostream>#include <unordered_map>using namespace std;typedef long long LL;const int mod = 1e9 + 7;int main() { int n; cin >> n; vector v(n); for (int i = 0; i < n; i++) { if (n % i == 0) v[i]++; } sort(v.begin(), v.end()); LL res = 1; for (auto prime : v) res = res * (prime.second + 1) % mod; cout << res << endl; return 0;} ```

正文

质数

在>1的整数中,如果只包含1和本身这两个约数,就被称为质数(素数)


866 试除法判定

866. 试除法判定质数 - AcWing题库

\(O(n)\)

bool isprime(int x) {
    if (x < 2) return false;
    for (int i = 2; i < x; i++)
        if (x % i == 0) return false;
    return true;
}

约数 d 与 n / d 成对出现,可以枚举较小的那一个 \(O(\sqrt{n})\)

\(d <= n/d \\ d^2 <= n \\ d <= \sqrt{n}\)

难点

  • 循环判断条件不要用 sqrt,每次循环都会执行一遍sqrt函数,比较慢
  • 循环判断条件不要用 i * i,存在溢出风险(变成负数)
  • 一定不会溢出的写法是 i <= n / i
#include <iostream>

using namespace std;

bool isprime(int n) {
    if (n < 2) return false;
    for (int i = 2; i <= n / i; i++)
        if (n % i == 0) return false;
    return true;
}

int main() {
    int n;
    cin >> n;
    while (n--) {
        int x;
        cin >> x;
        if (isprime(x))
            cout << "Yes" << endl;
        else
            cout << "No" << endl;
    }
}

867⭐分解质因数

867. 分解质因数 - AcWing题库

质因数指能整除给定正整数的质数。把一个合数分解成若干个质因数的乘积的形式,即求质因数的过程叫做分解质因数。

相关理论证明可看 数论——质数:分解质因数 - 知乎 (zhihu.com)

从2到\(\sqrt{n}\)枚举n的所有质因数,求其指数并输出。还要考虑最多有一个质因素大于\(\sqrt{n}\)的情况,单独判断输出。 最坏 \(O(\sqrt{n})\),最好 \(O(logn)\) (考虑\(2^k\)情况)

#include <iostream>

using namespace std;

void divide(int n) {
    for (int i = 2; i <= n / i; i++) {
        if (n % i == 0) {
            int cnt = 0;
            while (n % i == 0) {
                cnt++;
                n /= i;
            }
            cout << i << " " << cnt << endl;
        }
    }
    if (n > 1) cout << n << " " << 1 << endl;
}

int main() {
    int n;
    cin >> n;
    while (n--) {
        int x;
        cin >> x;
        divide(x);
        cout << endl;
    }
}

868⭐筛质数

868. 筛质数 - AcWing题库

朴素算法是从前往后删倍数(2~p-1都不是n的约数,所以n是质数)

调和级数\(1/2+1/3+1/4+1/5+...+1/∞\) 极限等于 \(lnn+C\)

\(lnn < log_2n\),因此朴素算法复杂度为 \(O(nlogn)\)


埃式筛法:只删除2~p-1中质数的倍数,原理跟867类似(算数基本定理:每个正整数都可以唯一表示成素数的乘积)

粗略估计:1~n当中,有\(n/lnn\)个质数,时间复杂度变为 \(O(n)\),真实复杂度 \(O(nloglogn)\),两者差不多一个级别

#include <algorithm>
#include <iostream>

using namespace std;

const int N = 1e6 + 10;
int primes[N], cnt;
bool st[N];

void get_primes(int n) {
    for (int i = 2; i <= n; i++) {
        if (!st[i]) {
            primes[cnt++] = n;
            for (int j = i + i; j <= n; j += i) st[j] = true;
        }
    }
}

int main() {
    int n;
    cin >> n;
    get_primes(n);
    cout << cnt << endl;

    return 0;
}

线性筛法,\(O(n)\),基本思路一样(基于每个质数的倍数为非质数),当 n 很大时,速度比埃式筛法快一倍。

每个数只会被其最小质因子筛掉

  • i % pj == 0,pj 一定是 i 的最小质因子,pj 一定是 pj * i 的最小质因子
  • i % pj != 0,pj 一定小于 i 的所有质因子,pj 一定是 pj * i 的最小质因子
#include <algorithm>
#include <iostream>

using namespace std;

const int N = 1e6 + 10;
int primes[N], cnt;
bool st[N];

void get_primes(int n) {
    for (int i = 2; i <= n; i++) {
        if (!st[i]) primes[cnt++] = i;
        for (int j = 0; primes[j] * i <= n; j++) {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;  // primes[j] 一定是 i 的最小质因子
        }
    }
}

int main() {
    int n;
    cin >> n;
    get_primes(n);
    cout << cnt << endl;

    return 0;
}

约数

869 试除法求约数

869. 试除法求约数 - AcWing题库

与866优化原理类似 \(O(\sqrt{n})\)

#include <algorithm>
#include <iostream>
#include <vector>

using namespace std;

vector<int> get_divisors(int n) {
    vector<int> res;
    for (int i = 1; i <= n / i; i++) {
        if (n % i == 0) {
            res.push_back(i);
            if (i != n / i) res.push_back(n / i);  // 避免平方
        }
    }
    sort(res.begin(), res.end());
    return res;
}

int main() {
    int n;
    cin >> n;
    while (n--) {
        int x;
        cin >> x;
        auto res = get_divisors(x);
        for (auto t : res) cout << t << ' ';
        cout << endl;
    }
}

870⭐约数个数

image-20230906120959871

利用算术基本定理,每个质因数有(1+n)种选择。m个选择组合得出m个约数

具体原理可看 第四章 数学知识(一)——质数与约数 - 知乎 (zhihu.com)

INT_MAX 约数个数约1500


870. 约数个数 - AcWing题库

求 n 个数的乘积的约数个数,可以求每个数的每个质因子指数之和,然后套用公式。

#include <algorithm>
#include <iostream>
#include <unordered_map>

using namespace std;

typedef long long LL;
const int mod = 1e9 + 7;

int main() {
    int n;
    cin >> n;
    unordered_map<int, int> primes;
    while (n--) {
        int x;
        cin >> x;
        for (int i = 2; i <= x / i; i++) {
            while (x % i == 0) {
                x /= i;
                primes[i]++;
            }
        }
        if (x > 1) primes[x]++;
    }
    LL res = 1;
    for (auto prime : primes) res = res * (prime.second + 1) % mod;
    cout << res << endl;
    return 0;
}

871⭐约数之和

AcWing 871. 约数之和 - AcWing

#include <algorithm>
#include <iostream>
#include <unordered_map>

using namespace std;

typedef long long LL;
const int mod = 1e9 + 7;

int main() {
    int n;
    cin >> n;
    unordered_map<int, int> primes;
    while (n--) {
        int x;
        cin >> x;
        for (int i = 2; i <= x / i; i++) {
            while (x % i == 0) {
                x /= i;
                primes[i]++;
            }
        }
        if (x > 1) primes[x]++;
    }
    LL res = 1;
    for (auto prime : primes) {
        int p = prime.first, a = prime.second;
        LL t = 1;
        while (a--) {
            t = (t * p + 1) % mod;
        }
        res = res * t % mod;
    }
    cout << res << endl;
    return 0;
}

872⭐最大公约数

872. 最大公约数 - AcWing题库

欧几里得算法(辗转相除法)

image-20230906122950118
#include <algorithm>
#include <iostream>
#include <unordered_map>

using namespace std;

// a 和 0 的最大公约数是 a
int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }

int main() {
    int n;
    cin >> n;
    while (n--) {
        int a, b;
        cin >> a >> b;
        cout << gcd(a, b) << endl;
    }
    return 0;
}

与C++算法之旅、08 基础篇 | 质数、约数相似的内容:

C++算法之旅、08 基础篇 | 质数、约数

算法学习笔记,记录容易忘记的知识点和难题。试除法、分解质因数、筛质数、约数个数、约数之和、最大公约数

C++算法之旅、09 力扣篇 | 常见面试笔试题(上)算法小白专用

算法学习笔记,记录容易忘记的知识点和难题。详解时空复杂度、50道常见面试笔试题,包括数组、单链表、栈、队列、字符串、哈希表、二叉树、递归、迭代、分治类型题目,均带思路与C++题解

详解共识算法的Raft算法模拟数

摘要:Raft算法是一种分布式共识算法,用于解决分布式系统中的一致性问题。 本文分享自华为云社区《共识算法之Raft算法模拟数》,作者: TiAmoZhang 。 01、Leader选举 存在A、B、C三个成员组成的Raft集群,刚启动时,每个成员都处于Follower状态,其中,成员A心跳超时为1

ACM算法竞赛代码模板(长期更新)

C++算法模板 基础算法 排序 快速排序 void quickSort(int q[], int l, int r) { if (l >= r) return; int i = l - 1, j = r + 1, x = q[l + r >> 1]; while (i < j) { do i ++

一个开源且全面的C#算法实战教程

前言 算法在计算机科学和程序设计中扮演着至关重要的角色,如在解决问题、优化效率、决策优化、实现计算机程序、提高可靠性以及促进科学融合等方面具有广泛而深远的影响。今天大姚给大家分享一个开源、免费、全面的C#算法实战教程:TheAlgorithms/C-Sharp。 C#经典十大排序算法(完结) 支持C

C#冒泡排序算法

冒泡排序实现原理 冒泡排序是一种简单的排序算法,其原理如下: 从待排序的数组的第一个元素开始,依次比较相邻的两个元素。 如果前面的元素大于后面的元素(升序排序),则交换这两个元素的位置,使较大的元素“冒泡”到右侧。 继续比较下一对相邻元素,重复步骤2,直到遍历到数组的倒数第二个元素。此时,最大的元素

C#插入排序算法

插入排序实现原理 插入排序算法是一种简单、直观的排序算法,其原理是将一个待排序的元素逐个地插入到已经排好序的部分中。 具体实现步骤如下 首先咱们假设数组长度为n,从第二个元素开始,将当前元素存储在临时变量temp中。 从当前元素的前一个位置开始向前遍历,比较temp与每个已排序元素的值大小。 如果已

C#堆排序算法

前言 堆排序是一种高效的排序算法,基于二叉堆数据结构实现。它具有稳定性、时间复杂度为O(nlogn)和空间复杂度为O(1)的特点。 堆排序实现原理 构建最大堆:将待排序数组构建成一个最大堆,即满足父节点大于等于子节点的特性。 将堆顶元素与最后一个元素交换:将最大堆的堆顶元素与堆中的最后一个元素交换位

【算法】用c#实现德州扑克卡牌游戏规则

德州扑克是一种牌类游戏,可多人参与,它的玩法是,玩家每人发两张底牌,桌面依次发5张公共牌,玩家用自己的两张底牌和5张公共牌自由组合,按大小决定胜负。 使用c#完成功能Hand()以返回手牌类型和按重要性递减顺序排列的等级列表,用于与同类型的其他手牌进行比较,即最佳手牌。 可能的手牌按价值降序排列:

【算法】用c#实现自定义字符串编码及围栏解码方法

编写一个函数/方法,它接受2个参数、一个字符串和轨道数,并返回ENCODED字符串。 编写第二个函数/方法,它接受2个参数、一个编码字符串和轨道数,并返回DECODED字符串。 然后使用围栏密码对其进行解码。 这种密码用于通过将每个字符沿着一组“竖状轨道”依次放在对角线上来对字符串进行编码。首先开始