【欧几里得算法】
在介绍扩展欧几里得算法之前,我先简单介绍一下欧几里得算法
欧几里得算法又称辗转相除法,用于计算两个整数a,b的最大公约数。
下面的 gcd(a,b)表示 a,b 的最大公约数,mod 是取余,div 是整除
其中有一个定理:gcd(a,b)= gcd(b,a mod b)
证明摘自百度(链接戳这里)
证明:a可以表示成 a = kb + r,则 r = a mod b
假设 d 是 a , b 的一个公约数,则有
d | a, d | b,而 r = a - kb,因此d | r
因此d是 ( b , a mod b ) 的公约数
假设d 是 ( b , a mod b ) 的公约数,则
d | b , d | r ,但是 a = kb + r
因此d也是 ( a , b ) 的公约数
那么 ( a , b ) 和 ( b , a mod b ) 的公约数是一样的,其最大公约数也必然相等,得证
所以说若我们不断地这样除下去,直到 a mod b 等于 0 时,答案就是 b
代码如下:
int gcd(int a,int b)
{
int r=a%b;
while(r!=0)
{
a=b;
b=r;
r=a%b;
}
return b;
}
【扩展欧几里得算法】
那么接下来是我们的重头戏——扩展欧几里得算法
定理:若 a,b 不全为 0,则存在整数 x 和 y,使得 ax + by = gcd(a,b)
有些问题要我们求出这样的方程的一组整数解
推导过程如下:
若 ,那么
我们可以找出一组 满足
一直这样下去(这是一个递归的过程),直到 时,此时 就是一组合法的解,再代回去就行了
代码如下:
void exgcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;
y=0;
return;
}
exgcd(b,a%b,y,x);
y-=a/b*x;
}
【例题】
例题传送门同余方程
这道题主要是要把原问题转换成 ax + by = 1 的形式,然后就可以用扩欧了
还有由于 x 要是正整数,所以输出答案时我们要把它转成正的,即 x = ( x + b ) % b
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
void exgcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;
y=0;
return;
}
exgcd(b,a%b,y,x);
y-=a/b*x;
}
int main()
{
int a,b,x,y;
scanf("%d%d",&a,&b);
exgcd(a,b,x,y);
printf("%d",(x+b)%b);
return 0;
}
另外,再推荐一道例题青蛙的约会,也是一道裸的模板题,A了可以去洛谷交一下这道题,感觉洛谷的数据强一些