扩展欧几里得算法的学习

第一部分:质数

质数

又称素数,有无限个。质数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数。
质数是一个孤独的数字呀!

质因数分解

什么是质因数分解?

就是将一个数字分解成几个质数相乘。小学时候我们就学过的,很简单。比如 9 = 3 × 3 9=3 \times 3 9=3×3;但是 64 = 8 × 8 64=8 \times8 64=8×8 就不对了,因为8不是质数啊!

这个有什么用?用处很大很大的!后面的求欧拉函数就是在这个的基础之上建立的。

代码:

#include<iostream>
#include<vector>
#include<cmath>
using namespace std;

vector<int> factor(int n)
{
	vector<int> ans;
	for (int i = 2; i <= sqrt(n); i++)
	{
		while (n%i == 0)
		{
			ans.push_back(i);
			n /= i;
		}
	}
	if (n > 1)
	{
		ans.push_back(n);
	}
	return ans;
}

int main()
{
	int n;
	cin >> n;
	vector<int>ans=factor(n);
	for (int i = 0; i < ans.size(); i++)
	{
		cout << ans[i] << " "; // 输出质因子
	}
}

欧拉函数

欧拉函数是什么?

在数论,对正整数 n n n,欧拉函数是小于 n n n的正整数中与 n n n互质的数的数目 φ ( 1 ) = 1 φ(1)=1 φ(1)=1。此函数以其首名研究者欧拉命名(Euler’so totient function)。 例如 φ ( 8 ) = 4 φ(8)=4 φ(8)=4,因为 1 , 3 , 5 , 7 均 和 8 1,3,5,7均和8 1,3,5,78互质。
这里有一个求欧拉函数的简便方法

###思路
基于上面的分解质因数的算法
###代码

XX

第二部分:求解不定方程

欧几里得算法

就是求两个数字a和b的最大公约数的。核心公式就是:$ gcd(a, b) = gcd(b, a%b) $ 不断的分下去,当 a % b a\%b a%b等于 0 0 0的时候 b b b就是答案了。

举例:$ gcd(9, 6) = gcd(6, 9%6)=gcd(6, 3)=gcd(3, 6%3)=gcd(3, 0)=3 $

为什么$gcd(a, b) = gcd(b, a%b) $成立呢?

证明:

假设 r r r a a a b b b 的最大公约数,那么有 r ∣ a r ∣ b r|a \quad r|b rarb

假设 c c c k k k都是任意整数,存在 a % b = c ⟺ k b + c = a ⟺ a − k b = c a\%b = c \Longleftrightarrow kb+c=a \Longleftrightarrow a-kb=c a%b=ckb+c=aakb=c

显然 r ∣ ( a − k b ) r|(a-kb) r(akb) 所以 r r r也是 a % b a\%b a%b的最大公约数,所以最大公约数存在 b b b a % b a\%b a%b内部。

扩展欧几里得算法


怎么证明是对的?

忘了

有什么用?

可以用来求 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)中的 x 和 y x和y xy的值。

那么问题来了如何求 a x + b y = z ax+by=z ax+by=z的值呢?

只需要将 $ax+by=gcd(a,b) 的 解 的解 x1和y1 扩 大 扩大 z/gcd(a,b)$倍就可以了。

举个例子:
我可以直接先求 3 x + 7 y = ( 3 , 7 ) 3x+7y=(3, 7) 3x+7y=(3,7)的解,也就是 3 x + 7 y = 1 3x+7y=1 3x+7y=1的解。我们得到 x = − 2 , y = 1 x=-2,y=1 x=2y=1。然后我们将 x 和 y x和y xy扩大 50 / ( 3 , 7 ) 50/(3, 7) 50/(3,7)倍,也就是 50 / 1 50/1 50/1倍,得到 x = − 2 ∗ 50 , y = 1 ∗ 50 x=-2*50, y=1*50 x=250,y=150。于是我们得到了 3 x + 7 y = 50 3x+7y=50 3x+7y=50的解是 − 100 和 50 -100和50 10050

代码

#include <iostream>
using namespace std;
int gcdEx(int a, int b, int &x, int &y) 
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    int r = gcdEx(b, a%b, x, y);
    int x1 = x, y1 = y;
    x = y1;
    y = x1 - (a / b) * y1;
    return r;
}
int main()
{
    int x, y;
    cout<<gcdEx(47, 30, x, y)<<"\n";
    cout<<x<<" "<<y;
    return 0;
}

解二元一次不定方程


###有什么卵用?
可以求逆元啊!!
同余方程可以转为不定方程,所以解同余方程可以看成解不定方程。

###代码

#include <iostream>
using namespace std;
int gcdEx(int a, int b, int &x, int &y)
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    int r = gcdEx(b, a%b, x, y);
    int x1 = x, y1 = y;
    x = y1;
    y = x1 - (a / b) * y1;
    return r;
}
int main()
{
    int x, y;
    int a, b, c; //ax+by=c
    cin >> a >> b>> c;
    int numGcd = gcdEx(a, b, x, y);
    cout << c / numGcd * x << " " << c / numGcd * y;
    return 0;
}

逆元


逆元是什么?逆天啊!
当a,m互质,若 a x ≡ 1 ( m o d m ) ax\equiv1(mod m) ax1(modm),则x是a关于模m的逆元。
###逆元有什么用?
我也不知道
###怎么求逆元
当a,m互质, a x ≡ 1 ( m o d m ) ax\equiv1(mod m) ax1(modm)。我们知道 a x ≡ 1 ( m o d m ) ax\equiv1(mod m) ax1(modm) 等价于 a x + m y = 1 ax+my=1 ax+my=1。那么 a x + m y = 1 ax+my=1 ax+my=1不就是个不定方程吗?直接用exgcd解不就行了吗?
注意解出的x可能是负数,如果是负数我们就直接加上m就行了。依据是不定方程通解公式,如下。
不定方程通解公式
###思路
就把它当做一个不定方程的问题来处理就行了。

###代码

#include<iostream>
#include<vector>
#include<cmath>
using namespace std;

int exgcd(int a, int b, int &x, int &y)
{
	if (b == 0)
	{
		x = 1;
		y = 0;
		return a;
	}

	int r = exgcd(b, a%b, x, y);
	int x1 = x;
	int y1 = y;
	x = y1;
	y = x1 - (a / b) * y1;
	return r;
}

// 求逆元
int inverse(int a, int m)
{
	int x, y;
	exgcd(a, m, x, y);
	return x;
}

int main()
{
	int a, m;
	cin >> a >> m;
	int ans = inverse(a, m);
	if (ans < 0)
	{
		cout << ans + m;
	}
	else
	{
		cout << ans;
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值