欧几里德(辗转相除法)
求最大公约数
int gcd(int a, int b)
{
if(b == 0)
return a;
return gcd(b, a%b);
}
优化版本
int gcd(int a,int b)
{
return b ? gcd(b,a%b) : a;
}
扩展欧几里德
求方程ax + by = gcd(a,b)的x,y的整数解;
——若a,b互质,则方程ax + by = 1有整数解(或者ax + by = 1 和 gcd(a,b)= 1 为充要条件)【裴蜀定理】
——如果ax + by = 1,且gcd(a,b) = 1,则方程有整数解【裴蜀定理】
——如果ax + by = 1,但是gcd(a,b) != 1,则方程ax + by = 1没有整数解【裴蜀定理】
证明:裴蜀定理(别称:贝祖定理)
方法一:
#include <bits/stdc++.h>
using namespace std;
int gcd(int a, int b, int& x, int& y)//x是求得的解,返回的值是a,b的最大公约数
{
int d = a;
if(b != 0)
{
d = gcd(b, a%b, y, x);
y -= (a/b)*x;
}
else
{
x = 1;
y = 0;
}
return d;
}
int main()
{
int x,y,a,b;
while(cin>>a>>b)
{
gcd(a,b,x,y);
while(x <= 0)//使得x为正数【很重要】
x += b;
cout<<x<<endl;
}
}
方法二:
#include <iostream>
using namespace std;
int ans_x, ans_y;//ans-x为所求方程的一个解
int gcd(int a,int b)//扩展欧几里德,返回的是a,b的最大公约数
{
if(b == 0)
{
ans_x = 1;
ans_y = 0;
return a;
}
int g = gcd(b,a%b);
int temp = ans_x;
ans_x = ans_y;
ans_y = temp - (a/b)*ans_x;
return g;
}
int main()
{
int a,b;
while(cin>>a>>b)
{
gcd(a,b);
while(ans_x <= 0)//使得ans_x为正数【很重要】
ans_x += b;
cout<<ans_x<<endl;
}
return 0;
}
乘法逆元
求解除法取模问题 (a/b)%m
【同余定理】a ≡ b (mod n) 的含义是“ a 和 b 关于模 n 同余”,即 a mod n = b mod n。其充要条件是: a-b 是 n 的整数倍(算法竞赛入门经典第二版P315)
【乘法逆元定义】a*x ≡ 1 (mod n) 的解 x 是 a 关于模 n 的逆(类似于实数运算中“倒数”的概念),即若 a*b%x = 1 则 a和b关于x互为逆元。它的充要条件是: gcd(a,x) = 1;
求解逆元 :
转化为扩展欧几里德 即 ax + by = 1,且 gcd(a,b) = 1 则称 a 和解 x 关于 b 互为逆元, b 和解 y 关于 a 互为逆元。
接着就能用扩展欧几里德求a或者b的逆元。
求解除法取模问题 (a/b)%m:
除以一个数取模等于乘以这个数的逆元取模(逆元相当于倒数)
证明:设b关于m的逆元为b',即b * b' % m = 1 或者 b * b'≡ 1(mod m)。
可得(a / b) % m = (a / b) % m * 1 = (a / b) % m * (b * b' % m) = (a / b) *(b * b') % m = a * b' %m