什么是欧几里得
是个变态
什么是欧几里得算法
gcd(a,b)=gcd(b,a%b)
好证不证了
什么是扩展欧几里得
求a*x+b*y=gcd(a,b)的解
对,是他,就是他
准备
- a*x+b*y=n*gcd(a,b) 一定有整数解
a,b,c为任意整数,如果x0,y0为方程 ax+by=c 的一组解,则方程的任意整数解都可以表示为(x0+n*b/gcd(a,b) ,y0-n*a/gcd(a,b)) ,n为任意整数。
很好证
x增加的:y减少的=b:a就好了若gcd(a, b) = d,则方程ax ≡ c (mod b)在[0, b/d - 1]上有唯一解。
- 若gcd(a, b) = 1,则方程ax ≡ c (mod b)在[0, b-1]上有唯一解。
开始
我们知道了一定存在 x 和 y 使得 : a*x + b*y = gcd , 那么,怎么求出这个特解 x 和 y 呢?只需要在欧几里德算法的基础上加点改动就行了。
我们观察到:欧几里德算法停止的状态是: a= gcd , b = 0 ,那么,这是否能给我们求解 x y 提供一种思路呢?因为,这时候,只要 a = gcd 的系数是 1 ,那么只要 b 的系数是 0 或者其他值(无所谓是多少,反正任何数乘以 0 都等于 0 但是a 的系数一定要是 1),这时,我们就会有: a*1 + b*0 = gcd
当然这是最终状态,但是我们是否可以从最终状态反推到最初的状态呢?
假设当前我们要处理的是求出 a 和 b的最大公约数,并求出 x 和 y 使得 a*x + b*y= gcd ,而我们已经求出了下一个状态:b 和 a%b 的最大公约数,并且求出了一组x1 和y1 使得: b*x1 + (a%b)*y1 = gcd , 那么这两个相邻的状态之间是否存在一种关系呢?
我们知道: a%b = a - (a/b)*b(这里的 “/” 指的是整除,例如 5/2=2 , 1/3=0),那么,我们可以进一步得到:
gcd = b*x1 + (a-(a/b)*b)*y1
= b*x1 + a*y1 – (a/b)*b*y1
= a*y1 + b*(x1 – a/b*y1)
对比之前我们的状态:求一组 x 和 y 使得:a*x + b*y = gcd ,是否发现了什么?
这里:
x = y1
y = x1 – a/b* y1
所以
如果得到ax ≡ c (mod b)的某一特解X,那么我令r = b/gcd(a, b),可知x在[0, r-1]上有唯一解,所以我用x = (X % r + r) % r就可以求出最小非负整数解x了!(X % r可能是负值,此时保持在[-(r-1), 0]内,正值则保持在[0, r-1]内。加上r就保持在[1, 2r - 1]内,所以再模一下r就在[0, r-1]内了)。
记下来吧
来一道题
poj —— 青蛙的约会
Description
两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置。不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的。但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面。
我们把这两只青蛙分别叫做青蛙A和青蛙B,并且规定纬度线上东经0度处为原点,由东往西为正方向,单位长度1米,这样我们就得到了一条首尾相接的数轴。设青蛙A的出发点坐标是x,青蛙B的出发点坐标是y。青蛙A一次能跳m米,青蛙B一次能跳n米,两只青蛙跳一次所花费的时间相同。纬度线总长L米。现在要你求出它们跳了几次以后才会碰面。
Input
输入只包括一行5个整数x,y,m,n,L,其中x≠y < 2000000000,0 < m、n < 2000000000,0 < L < 2100000000。
Output
输出碰面所需要的跳跃次数,如果永远不可能碰面则输出一行”Impossible”
Sample Input
1 2 3 4 5
Sample Output
4
这道题不难
真的不难
思路思路思路
求一个k,使x + k*m ≡ y + k*n (mod L)
然后对方程化简,就变成(n-m) * k ≡ x-y (mod L)。
??
what ??
咋化简啊??
来定理
很容易化简了吧╮(╯▽╰)╭
然后这个方程其实就等价于(n-m)*k + L*s = x-y。
这就是ax + by = c求整数x的模型。
#include <iostream>
using namespace std;
long long extgcd(long long a, long long b, long long &x, long long &y)
{
long long d, t;
if (b == 0) { x = 1; y = 0; return a; } //递归最后得到的解
d = extgcd(b, a % b, x, y);
t = x - a / b * y; x = y; y = t;//用后面的解表示前面的解
return d;//return 最大公约数
}
int main()
{
long long x, y, m, n, L, X, Y, d, r;
while (cin >> x >> y >> m >> n >> L)
{
d = extgcd(n - m, L, X, Y); r = L / d;//extgcd有两个作用 1.找出最小公倍数下面判断 2.找解
if ((x - y) % d) cout << "Impossible" << endl;//判断(x-y)是不是d的倍数
else cout << ((x - y) / d * X % r + r) % r << endl;//求最小正整数解,原理讲过了
}
return 0;
}
我写的太辣鸡啦qwq
看看大神Orz
本文详细介绍了扩展欧几里得算法的概念及其应用,包括如何求解线性方程的整数解,并通过实例解释了算法的具体实现过程。
940

被折叠的 条评论
为什么被折叠?



