数学知识:欧拉函数,快速幂,扩展欧几里得,线性同余方程 讲解

🎬 博主名称个人主页

🔥 个人专栏 : 《算法通关》《Java讲解》

⛺️心简单,世界就简单

序言

哎数学还挺难的哈,下面讲点数论知识

目录

欧拉函数

利用定义求欧拉函数

利用筛法求欧拉函数

快速幂

快速幂求逆元

裴蜀定理

扩展欧几里得

看数学推导

线性同余方程

欧拉函数

这个意思是 1 ~ n 内与 n 互质的个数

我们来看一下过程

分解n的质因数 :

举个例子 6 = 2 * 3,他的互质个数就是6 * ( 1 - 1 / 2) * ( 1 - 1/ 3) = 6 * 1 / 2 * 2 / 3 = 2

所以与6互质的个数就是2

推导用的是容斥原理,这里就不细说,就直接看上面这个公式就行

利用定义求欧拉函数

cpp 复制代码
#include<iostream>
#include<algorithm>

using namespace std;

int main(){
	int n;
	cin >> n;
	
	while(n --){
		int a; 
		cin >> a;
		
		int res = a;
		for(int i = 2; i <= a / i; i ++){
			if(a % i == 0) {
				res = res / i * (i - 1);
				//等价于res = res * (1 - 1 / i)  
				while(a % i == 0) a /= i;
			}
		}
			if(a > 1)res = res / a * (a -1);
	
		cout << res << endl;
	}

}

利用筛法求欧拉函数

这个其实不太好推

cpp 复制代码
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long LL;
const int N = 1000010;

int primes[N], cnt;  // 存储所有质数
int phi[N];         // 存储每个数的欧拉函数值
bool st[N];         // 标记是否是合数,st[i]=true表示i是合数

LL get_eulers(int n){
    phi[1] = 1;  // 规定φ(1)=1
    
    for(int i = 2; i <= n; i++){
        if(!st[i]){  // 如果i是质数
            primes[cnt ++] = i;  // 存储质数
            phi[i] = i - 1;      // 性质1:质数p的φ(p)=p-1
        }
        
        // 用当前已知的质数去筛i的倍数
        for(int j = 0; primes[j] <= n / i; j ++){
            st[primes[j] * i] = true;  // 标记合数
            
            if(i % primes[j] == 0){  // 如果primes[j]是i的质因子
                // 性质2:如果p整除n,则φ(p×n)=p×φ(n)
                phi[primes[j] * i] = primes[j] * phi[i];
                break;  // 保证每个合数只被最小质因子筛
            }
            // 性质3:如果p不整除n,则φ(p×n)=(p-1)×φ(n)
            phi[primes[j] * i] = (primes[j] - 1) * phi[i];
        }
    }
    
    // 计算前缀和
    LL res = 0;
    for(int i = 1; i <= n; i ++) res += phi[i];
    return res;
}

快速幂

先说一下快速幂是来处理什么问题的,他是用来快速求出 a ^ k mod P的结果,在o( log k)的时间复杂度求出结果

这个就比较简单了,其实就是让这个k转化为2进制,求出每一个是1的位的幂,然后我妈有了这些直接进行相加就行

cpp 复制代码
#include<iostream>
#include<algorithm>

using namespace std;

int main(){
	int n;
	cin >> n;
	
	while(n --){
		int a; 
		cin >> a;
		
		int res = a;
		for(int i = 2; i <= a / i; i ++){
			if(a % i == 0) {
				res = res / i * (i - 1);
				//等价于res = res * (1 - 1 / i)  
				while(a % i == 0) a /= i;
			}
		}
			if(a > 1)res = res / a * (a -1);
	
		cout << res << endl;
	}

}

快速幂求逆元

之前文章也讲过这个,具体可以看之前的文章,我们这里只给个求逆元的模板

cpp 复制代码
#include<iostream>
#include<algorithm>

using namespace std;

typedef long long LL;

int n;

// a^k %p
int qmi(int a, int k, int p){
	int res = 1;
	while(k){
		if(k & 1) res = (LL)res * a % p;
		k >>= 1;
		a = (LL)a * a % p;
	}
	return res;
}

int main(){
	scanf("%d", &n);
	while(n --){
		int a, p;
		scanf("%d%d", &a, &p);
		
		int res = qmi(a, p - 2, p);
		
		if(a % p) printf("%d\n", res);
		else puts("impossible");
	}
} 

裴蜀定理

有一对正整数a, b,那么存在整数x, 使得ax + by = gcd(a, b)

如果ax + by = d,那么d一定是gcd(a, b)的倍数,所以可以凑出最小的a,b的系数正好是的=最大公约数

扩展欧几里得

看数学推导

我们要解:a × x + b × y = gcd(a, b)

假设我们已经递归计算了下一层:
b × x₁ + (a % b) × y₁ = gcd(b, a % b)

根据欧几里得算法:gcd(a, b) = gcd(b, a % b)

展开 a % b = a - ⌊a/b⌋ × b

复制代码
b × x₁ + (a % b) × y₁ 
= b × x₁ + (a - ⌊a/b⌋ × b) × y₁
= a × y₁ + b × (x₁ - ⌊a/b⌋ × y₁)

比较一下

复制代码
x = y₁
y = x₁ - ⌊a/b⌋ × y₁

所以就得到了下面这个

cpp 复制代码
	int d =  exgcd(b, a % b, y, x);
	y -= a / b * x;
	return d;
cpp 复制代码
#include<iostream>

using namespace std;

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

int main(){
	int n;
	scanf("%d", &n);
	
	while(n --){
		int a, b, x, y;
		scanf("%d%d", &a, &b);
		exgcd(a, b, x, y);
		printf("%d %d\n", x, y);
	}
}

线性同余方程

这个就是转化为扩展欧几里得的形式去求

cpp 复制代码
#include<iostream>

using namespace std;

typedef long long LL;


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

int main(){
	int n;
	scanf("%d", &n);
	
	while(n --){
		int a, b, m;
		scanf("%d%d%d", &a, &b, &m);
		int x, y;
		int d = exgcd(a, m, x, y);
		if(b % d) puts("impossible");
		else printf("%d\n", (LL)x * (b / d) % m);
	}
}
相关推荐
徐小夕4 小时前
pxcharts Ultra V2.3更新:多维表一键导出 PDF,渲染兼容性拉满!
vue.js·算法·github
CoovallyAIHub5 小时前
OpenClaw一脚踩碎传统CV?机器终于不再只是看世界
深度学习·算法·计算机视觉
CoovallyAIHub5 小时前
仅凭单目相机实现3D锥桶定位?UNet-RKNet破解自动驾驶锥桶检测难题
深度学习·算法·计算机视觉
zone77395 小时前
002:RAG 入门-LangChain 读取文本
后端·算法·面试
樱木Plus5 小时前
深拷贝(Deep Copy)和浅拷贝(Shallow Copy)
c++
得物技术6 小时前
得物社区搜推公式融合调参框架-加乘树3.0实战
算法
会员源码网1 天前
使用`mysql_*`废弃函数(PHP7+完全移除,导致代码无法运行)
后端·算法
木心月转码ing1 天前
Hot100-Day10-T438T438找到字符串中所有字母异位词
算法
HelloReader1 天前
Wi-Fi CSI 感知技术用无线信号“看见“室内的人
算法
颜酱1 天前
二叉树分解问题思路解题模式
javascript·后端·算法