数论——裴蜀定理、欧几里得算法、扩展欧几里得算法、逆元以及求解

news2024/9/21 4:38:30
裴蜀定理

若整数 ab 互质(最大公约数为 1),则存在整数 xy ,使得 ax + by = 1 。

更一般的情况是:设 ab 是不全为零的整数,则存在整数 xy ,使得 ax + by = gcd(a, b) ,其中 gcd(a, b) 表示 a 和 b 的最大公约数。

裴蜀定理有以下几个重要的应用:

求解线性不定方程:例如给定方程 3x + 5y = 7 ,可以利用裴蜀定理判断是否有整数解。

在数论中的证明:帮助证明其他与整数相关的定理和结论。

求解模运算中的问题:比如在某些同余方程的求解中发挥作用。

BZOJ1441——Min

Min - 题目详情 - BZOJ by HydroOJ

#include<iostream>
#include<math.h>
using namespace std;
int gcd(int a, int b) {
	return (b == 0) ? a : gcd(b, a % b);
}
int main() {
    int n, m[10010];
    int ret = 0;
    cin >> n;
    cin >> m[0];
    ret = m[0];
    for(int i=1;i<n;i++){
        cin >> m[i];
        ret = gcd(ret,m[i]);
	}
    cout << abs(ret) << endl;
}

整体框架

  • 包含了必要的输入输出流和数学库的头文件。
  • 在 main 函数中进行主要的操作。

函数 gcd

  • 这是一个用于计算两个数最大公约数的递归函数。
  • 基于欧几里得算法,当 b 为 0 时,返回 a 作为最大公约数;否则,通过递归调用计算 b 和 a % b 的最大公约数。

main 函数

  • 首先读取一个整数 n ,表示接下来要输入的数的个数。
  • 读入第一个数 m[0] ,并将其初始化为 ret 。
  • 然后通过一个循环,依次读入后续的数 m[i] ,并不断更新 ret 为它与当前 m[i] 的最大公约数。
  • 最后输出计算得到的最大公约数的绝对值。
欧几里得算法(辗转相除法)

a|b表示a整除b;如3|6;a<b

a|\b表示a不整除b;如5|\7;

|可以表示对整数的划分;

int gcd(int a,int b){
return (b==0)?a:gcd(b,a%b);
}
#include<iostream>
using namespace std;
int gcd(int a, int b) {
	return (b == 0) ? a : gcd(b, a % b);
}
int main() {
	int a, b;
	while(cin >> a >> b){
	cout << gcd(a, b) << endl;
}
}
扩展欧几里得算法

int extend_gcd(int a, int b, int& x, int& y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    } else {
        int ret = extend_gcd(b, a % b, y, x);
        y -= x * (a / b);
        return ret;
    }
}
#include<iostream>
using namespace std;
int extend_gcd(int a, int b, int& x, int& y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    else {
        int ret = extend_gcd(b, a % b, y, x);
        y -= x * (a / b);
        return ret;
    }
}
int main() {
    int a, b, x, y;
    while (cin >> a >> b >> x >> y) {
        cout << extend_gcd(a, b, x, y) << endl;
        return 0;
    }
}
逆元

  1. 在密码学中的应用:例如在 RSA 加密算法中,逆元的计算是关键步骤之一。

  2. 用于优化计算:在涉及模运算的复杂计算中,使用逆元可以简化计算过程,提高效率。

计算逆元的方法通常包括扩展欧几里得算法、费马小定理等。

扩展欧几里得算法求逆元

int inverse(int a, int b) {
    int x, y;
    extend_gcd(a, b, x, y);
    return x;
}
#include <iostream>

// 扩展欧几里得算法函数
int extendedEuclidean(int a, int b, int& x, int& y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }

    int x1, y1;
    int gcd = extendedEuclidean(b, a % b, x1, y1);

    x = y1;
    y = x1 - (a / b) * y1;

    return gcd;
}

// 计算逆元的函数
int modInverse(int a, int m) {
    int x, y;
    int gcd = extendedEuclidean(a, m, x, y);
    if (gcd!= 1) {
        std::cout << "Inverse doesn't exist" << std::endl;
        return -1;
    } else {
        return (x % m + m) % m;
    }
}

int main() {
    int a = 3, m = 11;
    int inv = modInverse(a, m);
    if (inv!= -1) {
        std::cout << "Inverse of " << a << " mod " << m << " is " << inv << std::endl;
    }

    return 0;
}
  1. extendedEuclidean 函数:

    • 这个函数使用递归的方式实现扩展欧几里得算法。
    • 如果 b 为 0 ,则直接设置 x 为 1 ,y 为 0 ,并返回 a ,此时 a 就是最大公约数。
    • 否则,通过递归调用自身计算 b 和 a % b 的最大公约数以及对应的解 x1 和 y1 。
    • 然后根据递归返回的结果计算当前层的 x 和 y 。
  2. modInverse 函数:

    • 首先调用 extendedEuclidean 函数计算 a 和 m 的最大公约数以及对应的解 x 和 y 。
    • 如果最大公约数不为 1 ,说明逆元不存在,输出提示信息并返回 -1 。
    • 如果最大公约数为 1 ,则通过计算 (x % m + m) % m 得到逆元并返回。这里加上 m 再取模是为了确保结果为正数。
  3. main 函数:

    • 定义了整数 a 和 m 。
    • 调用 modInverse 函数计算 a 模 m 的逆元,并根据返回结果进行输出。
欧拉定理求逆元

int power_mod(int a, int b, int n) {
    int ret = 1;
    while (b) {
        if (b & 1)
            ret = (long long)ret * a % n;
        a = (long long)a * a % n;
        b >>= 1;
    }
    return ret;
}
#include<iostream>
using namespace std;
int power_mod(int a, int b, int n) {
    int ret = 1;
    while (b) {
        if (b & 1)
            ret = (long long)ret * a % n;
        a = (long long)a * a % n;
        b >>= 1;
    }
    return ret;
}

int main() {
    int a, b,n;
    while (cin >> a >> b >>n) {
        cout << power_mod(a, b, n) << endl;
    }
        return 0;
    }
线性求逆元:递推法
for (inverse[1] = 1, i = 2; i <= n; ++i)
    inverse[i] = inverse[p % i] * (p - p / i) % p;
线性求逆元:倒推法

#include <iostream>

const int MOD = 1000000007;
const int MAXN = 100005;

int inv[MAXN];

void calculateInverse(int n) {
    inv[1] = 1;
    for (int i = 2; i <= n; i++) {
        inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD;
    }
}

int main() {
    int n = 5;
    calculateInverse(n);
    for (int i = 1; i <= n; i++) {
        std::cout << "Inverse of " << i << " is: " << inv[i] << std::endl;
    }
    return 0;
}
  • 首先定义一个常量 MOD 表示模数,一个常量 MAXN 表示可能的最大数的范围,以及一个数组 inv 来存储每个数的逆元。

  • 在 calculateInverse 函数中,先初始化 inv[1] = 1 ,因为 1 的逆元就是 1 。

  • 对于大于 1 的数 i ,通过公式 inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD 来计算逆元。这个公式的推导基于数论的知识。

  • 在 main 函数中,指定要计算逆元的数的范围 n ,调用 calculateInverse 函数进行计算,然后输出每个数的逆元。

POJ1845——Sumdiv

1845 -- Sumdiv

BZOJ2186——沙拉公主的困惑

[Sdoi2008]沙拉公主的困惑 - 题目详情 - BZOJ by HydroOJ
#include <cstdio>
#include <algorithm>

using namespace std;

inline void exgcd (int a, int b, int &x, int &y)
{
	if(b == 0) { x = 1; y = 0; return ; }
	else { exgcd(b, a%b, x, y); int tmp = x; x = y; y = tmp - a / b * y; }
}

inline int getinv (int a, int p)
{
	int x, y;
	exgcd(a, p, x, y);
	return (x%p+p)%p;
}

bool np[10000005];
int l, p[664580];
long long fac[10000005];
long long inv[664580];
long long mul[664580];

int main (void)
{
	int t, mod, n, m;
	scanf("%d %d", &t, &mod);
	fac[1] = 1; np[0] = np[1] = 1;
	inv[0] = 1; mul[0] = 1;
	for(register int i=2; i<=10000000; ++i)
	{
		fac[i] = fac[i-1] * i % mod;
		if(!np[i])
		{
			p[++l] = i;
			inv[l] = inv[l-1] * getinv(p[l], mod) % mod;
			mul[l] = mul[l-1] * (p[l] - 1) % mod;
		}
		for(register int j=1; j<=l; ++j)
		{
			if(i*p[j]>10000000) break;
			np[i*p[j]] = 1;
			if(i%p[j]==0) break;
		}
	}
	while(t--)
	{
		scanf("%d %d", &n, &m);
		register int mid = upper_bound(p+1,p+l+1,m)-p-1;
		printf("%lld\n", fac[n] * inv[mid] % mod * mul[mid] % mod);
	}
	return 0;
}

整体框架

  • 首先包含了必要的头文件,并定义了一些函数和变量。
  • 在 main 函数中处理输入的测试用例,进行相关计算并输出结果。

函数 exgcd

  • 这是扩展欧几里得算法,用于求解线性方程 ax + by = gcd(a, b) 中的 x 和 y
  • 通过递归的方式,当 b 为 0 时直接确定 x 和 y 的值,否则在递归后交换 x 和 y 的值,并进行相应的计算来更新 y

函数 getinv:利用 exgcd 函数来计算 a 在模 p 意义下的逆元。

预处理部分

  • 初始化一些数组和变量,如 np 数组标记是否为合数,p 数组存储质数,fac 数组存储阶乘值,inv 数组存储质数逆元的乘积,mul 数组存储质数减 1 的乘积。
  • 通过两层循环来筛选出质数,并计算相关的值。

测试用例处理部分

  • 每次读入 n 和 m
  • 通过二分查找找到小于等于 m 的最大质数的索引 mid
  • 最终计算并输出 fac[n] * inv[mid] % mod * mul[mid] % mod 的结果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1977463.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第十一章:Kubernetes API服务器的安全防护

本章内容包括&#xff1a; 了解认证机制ServiceAccounts是什么及使用的原因了解基于角色(RBAC)的权限控制插件使用角色和角色绑定使用集群角色和集群角色绑定了解默认角色及其绑定 1 了解认证机制 在前面的内容中&#xff0c;我们说到API服务器可以配置一个到多个认证的插件(授…

等保2.0 | 人大金仓数据库测评

人大金仓数据库&#xff0c;全称为金仓数据库管理系统KingbaseES&#xff08;简称&#xff1a;金仓数据库或KingbaseES&#xff09;&#xff0c;是北京人大金仓信息技术股份有限公司自主研制开发的具有自主知识产权的通用关系型数据库管理系统。以下是关于人大金仓数据库的详细…

室内养宠空气净化器哪家好?热门室内养宠空气净化器用户体验

自从家里有了4只英短后&#xff0c;一到季节我就得不停的拖地刷床&#xff0c;除了这些可以手动清理的猫毛之外&#xff0c;那么空气中的猫毛怎么办&#xff1f;真的不建议养猫&#xff0c;除非你能接受空气中飞舞着浮毛&#xff0c;衣服、床、筷子、鼻子里全都是猫毛&#xff…

STM32——外部中断(EXTI)

目录 前言 一、外部中断基础知识 二、使用步骤 三、固件库实现 四、STM32CubeMX实现 总结 前言 外部中断&#xff08;External Interrupt&#xff0c;简称EXTI&#xff09;是微控制器用于响应外部事件的一种方式&#xff0c;当外部事件发生时&#xff08;如按键按下、传感器信号…

NC 合并区间

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了就去分享给你的码吧。 描述 给出一组区间…

推流直播服务

pc端建立NVR服务器&#xff0c;并实现NVR功能&#xff0c;具有推流功能&#xff0c;推送给OBS&#xff0c;可以对接到抖音、快手等平台&#xff0c;实现实时直播&#xff0c;应用于无人值守&#xff0c;养殖、农场、旅游等场景 运行MediaServer和webserver 服务端口配置在confi…

C# 使用 NLog 输出日志到文件夹

在项目中使用 NuGet 安装 NLog 包以及 NLog.Config 包 配置 nlog.config 在项目的根目录下创建一个 Nlog.config 文件&#xff08;如果还没有&#xff09;&#xff0c;然后添加如下配置&#xff1a; <?xml version"1.0" encoding"utf-8" ?> <…

leetcode数论(​3044. 出现频率最高的质数)

前言 经过前期的基础训练以及部分实战练习&#xff0c;粗略掌握了各种题型的解题思路。现阶段开始专项练习。 描述 给你一个大小为 m x n 、下标从 0 开始的二维矩阵 mat 。在每个单元格&#xff0c;你可以按以下方式生成数字&#xff1a; 最多有 8 条路径可以选择&#xff1…

17 字符函数、字符串函数和内存函数

目录 一、字符函数 &#xff08;一&#xff09;字符分类函数 &#xff08;二&#xff09;字符转换函数 二、字符串函数 &#xff08;一&#xff09;strlen、strcpy、strcat、strcmp的使用和模拟实现 1、strlen &#xff08;1&#xff09;使用 &#xff08;2&#xff09;…

Java中的5种线程池类型

Java中的5种线程池类型 1. CachedThreadPool &#xff08;有缓冲的线程池&#xff09;2. FixedThreadPool &#xff08;固定大小的线程池&#xff09;3. ScheduledThreadPool&#xff08;计划线程池&#xff09;4. SingleThreadExecutor &#xff08;单线程线程池&#xff09;…

基于切片法计算点云体积 双向最近点三维点排序

具体内容源代码&#xff1a;基于切片法计算点云体积 双向最近点三维点排序 效果 主要方法&#xff1a; 点云切片&#xff08;基于一定厚度度的点云切片投影&#xff09; &#xff1b;切片后的点云分割 &#xff1b;边缘点排序【双向最近邻】&#xff08;可以进行多边形拟合计…

JAVA项目基于Spring Boot的美食烹饪互动平台的设计与实现

目录 一、前言 二、技术介绍 三、系统实现 四、论文参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 随着互联网…

复盘:项目负责人的经验之谈

复盘&#xff1a;项目负责人的经验之谈 前言基础复盘&#xff1a;从无到有的自我觉醒客观分析&#xff1a;数据驱动的决策专业工具&#xff1a;科学分析的利器模型构建&#xff1a;从个案到普遍规律的提炼能力提升&#xff1a;从知识到行动的转变结语 前言 在项目管理和竞赛的世…

SOMEIP_ETS_002:数组长度过长

测试目的&#xff1a; 确保DUT在接收到的SOME/IP消息中数组长度超出实际数组长度时&#xff0c;能够返回错误消息。 描述 本测试用例旨在验证当DUT接收到一个声明数组长度超过其实际长度的SOME/IP消息时&#xff0c;DUT是否能够正确地返回错误消息&#xff08;MALFORMED_MES…

高并发下的分布式缓存 | 设计和实现LFU缓存

什么是 LFU 缓存&#xff1f; 最少使用频率 (LFU) 是一种用于管理计算机内存的缓存算法。在这种算法中&#xff0c;系统会跟踪缓存中每个数据被引用的次数。当缓存已满时&#xff0c;系统会删除引用频率最低的数据。 LFU 缓存问题描述 我们的目标是设计一个LFU 缓存&#xf…

手机号码归属地数据源,让您随时掌握通话对方位置!

手机号码归属地数据源&#xff0c;这是一个非常实用的数据源&#xff0c;可以帮助我们随时掌握通话对方的位置。无论是普通民众还是企业用户&#xff0c;都可以从中受益。 在这个数据源中&#xff0c;我们可以通过手机号码的前7位来查询该手机号码的归属地&#xff0c;包括省市…

美容院管理小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;服务类型管理&#xff0c;产品服务管理&#xff0c;预约信息管理&#xff0c;产品分类管理&#xff0c;产品信息管理&#xff0c;订单管理&#xff0c;系统管理 微信端账号功能包…

笔试练习day2

目录 BC64 牛牛的快递题目解析解法模拟代码方法1方法2 DP4 最小花费爬楼梯题目解析解法动态规划状态表示状态转移方程代码 数组中两个字符串的最小距离题目解析解法方法1暴力解法(会超时)方法2贪心(动态规划)代码 感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接…

【数据脱敏】数据交换平台数据脱敏建设方案

1 概述 1.1 数据脱敏定义 1.2 数据脱敏原则 1.2.1基本原则 1.2.2技术原则 1.2.3管理原则 1.3 数据脱敏常用方法 3.1.1泛化技术 3.1.2抑制技术 3.1.3扰乱技术 3.1.4有损技术 1.4 数据脱敏全生命周期 2 制定数据脱敏规程 3 发现敏感数据 4 定义脱敏规则 5 执…

GD32 IAP升级——boot和app相互切换

GD32 IAP升级——boot和app相互切换 目录 GD32 IAP升级——boot和app相互切换1 Keil工程设置1.1 修改ROM1.2 Keil烧录配置 2 代码编写2.1 app跳转2.2 软件重启2.3 app中断向量表偏移 结束语 1 Keil工程设置 1.1 修改ROM GD32内部Flash是一整块连续的内存&#xff0c;但是因为…