扩展欧几里得算法的学习

第一部分:质数

质数

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

质因数分解

什么是质因数分解?

就是将一个数字分解成几个质数相乘。小学时候我们就学过的,很简单。比如9=3×39=3 \times 39=3×3;但是 64=8×864=8 \times864=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] << " "; // 输出质因子
	}
}

欧拉函数

欧拉函数是什么?

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

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

XX

第二部分:求解不定方程

欧几里得算法

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

举例:$ 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) $成立呢?

证明:

假设rrraaabbb 的最大公约数,那么有r∣ar∣br|a \quad r|brarb

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

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

扩展欧几里得算法


怎么证明是对的?

忘了

有什么用?

可以用来求 ax+by=gcd(a,b)ax+by=gcd(a,b)ax+by=gcd(a,b)中的x和yx和yxy的值。

那么问题来了如何求ax+by=zax+by=zax+by=z的值呢?

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

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

代码

#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互质,若ax≡1(modm)ax\equiv1(mod m)ax1(modm),则x是a关于模m的逆元。
###逆元有什么用?
我也不知道
###怎么求逆元
当a,m互质,ax≡1(modm)ax\equiv1(mod m)ax1(modm)。我们知道ax≡1(modm)ax\equiv1(mod m)ax1(modm) 等价于ax+my=1ax+my=1ax+my=1。那么ax+my=1ax+my=1ax+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;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值