第四节——基础数学—整除、同余、素数、唯一分解定理等概念;GCD 及相关知识:辗转相除法、裴蜀定理; 线性筛; 乘法逆元

引言

在编程和算法设计中,基础数学知识扮演着至关重要的角色。本文将探讨几个核心数学概念及其在编程中的应用,包括整除、同余、素数、唯一分解定理、最大公约数(GCD)、线性筛和乘法逆元。

整除与同余

整除和同余是数论中的基础概念。整除涉及到一个整数能被另一个整数整除的情况,而同余则涉及到除法的余数。

  • 应用:在处理周期性问题、计算模运算时,同余性质尤为重要。

素数与唯一分解定理

素数是只有1和它本身两个正因数的自然数。唯一分解定理表明,每个大于1的自然数都可以唯一地分解为素数的乘积。

最大公约数(GCD)

两个整数的最大公约数(GCD)是能同时整除这两个数的最大正整数。辗转相除法(欧几里得算法)是计算GCD的经典方法。

  • 应用:在简化分数、解决线性不定方程组等问题中,GCD都非常重要。

线性筛

线性筛是一种高效的算法,用于计算一定范围内所有质数。

  • 应用:在解决整数规划问题场景中,线性筛提供了一种快速预处理数据的方法。

乘法逆元

在模运算中,乘法逆元是指一个数,使得该数与给定数相乘后模结果为1。

  • 应用:在解决线性同余方程组时,乘法逆元用于调整方程。

题目分析:

1.有理数取余

可以根据同余的性质a-b=km(k为整数),a与b模m同余计算

AC记录及代码如下

2.Minimal Coprime

显然,最小组合一定是相邻的两个数,需要注意l和r都为1的情况,其余直接计算。

AC记录及代码如下

3.素数密度

该题可以先筛出50000内的素数,随后用这些素数去筛选出l_r之间合数的个数(由于50000内素数一共几千个,且不会全部遍历完,所以筛选不会超时

AC记录及代码如下

4.最大公约数和最小公倍数问题

由于两个数的乘积与这两个数的最大公约数和最小公倍数的乘积相同,除去两数相等的情况,其余可以以步长为最小公因数遍历判断是否满足题意(两数顺序不同算不同情况,所以仅仅需要遍历前一个数小于后一个数,每一次判断成功答案加二)

AC记录及代码如下

5.Longest Subsequence

首先先对原数组处理,小于m的数剔除,然后对数列的每个元素的数量计数,然后从lcm最大开始递减筛选,判断满足数量的长度(个数),记录最长序列。最后输出。

AC记录及代码如下

6.Common Generator

预处理使用线筛法标记所有非素数,并记录素数。对于每个非素数,计算一个“特定值”(sv),表示它可能的最小生成器。

对于每一个用例:

  • 遍历数组,检查每个数是否为素数:如果所有数都是同一个素数,该素数就是共同生成器。

  • 如果存在多个不同的素数,直接输出 −1。

  • 如果数组中没有素数,输出 2(最小生成器)。

  • 对于非素数,验证其“特定值”是否小于当前的共同生成器。如果存在不符合条件的数,输出 −1。

AC代码如下:

#include <iostream>
#include <cstring>
using namespace std;
const int ma = 4e5 + 10;
bool np[ma];
int sv[ma];
int p[ma];
int pc = 0;
int nums[ma];
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int tc;
    cin >> tc;
    np[1] = true;
    for (int i = 2; i <= ma; i++) {
        if (!np[i]) {
            p[pc++] = i;
        }
        for (int j = 0; j < pc && i * p[j] <= ma; j++) {
            int c = i * p[j];
            np[c] = true;
            if (c % 2 == 0) {
                sv[c] = c / 2;
            }
            else {
                sv[c] = p[j] * (i - 1) / 2;
            }
            if (i % p[j] == 0) {
                break;
            }
        }
    }
    while (tc--) {
        int n;
        cin >> n;
        for (int i = 0; i < n; i++) {
            cin >> nums[i];
        }
        int cg = 0;
        for (int i = 0; i < n; i++) {
            if (!np[nums[i]]) {
                if (cg == 0 || cg == nums[i]) {
                    cg = nums[i];
                }
                else {
                    cg = -1;
                }
            }
        }
        if (cg == -1) {
            cout << cg << '\n';
        }
        else if (cg == 0) {
            cout << 2 << '\n';
        }
        else {
            for (int i = 0; i < n; i++) {
                if (cg != nums[i] && sv[nums[i]] < cg) {
                    cg = -1;
                }
            }
            cout << cg << '\n';
        }
    }
    return 0;
}

结语

基础数学为理解和设计高效算法提供了理论基础。掌握这些数学概念不仅对解决数学问题至关重要,对编程和算法设计同样重要。随着你对这些概念理解的加深,你将设计出更加高效的算法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值