扩展GCD
引入
扩展欧几里得算法,简称 exgcd,一般用来求解不定方程,求解线性同余方程,求解模的逆元等
引理:存在 x , y 使得 gcd(a,b)=ax+by
证明:
当 b=0 时,gcd(a,b)=a,此时 x=1 , y=0
当 b!=0 时,
设 ax1+by1=gcd(a,b)=gcd(b,a%b)=bx2+(a%b)y2
又因 a%b=a-a/b*b
则 ax1+by1=bx2+(a-a/b*b)y2
ax1+by1=bx2+ay2-a/b*by2
ax1+by1=ay2+bx2-b*a/b*y2
ax1+by1=ay2+b(x2-a/b*y2)
解得 x1=y2 , y1=x2-a/b*y2
因为当 b=0 时存在 x , y 为最后一组解
而每一组的解可根据后一组得到
所以第一组的解 x , y 必然存在
CODE:
void exgcd(int a, int b, int &x, int &y) { if(b == 0) x = 1, y = 0; else exgcd(b, a % b, y, x), y -= a / b * x; }
exgcd 解不定方程(使用不将a与b转为互质的方法)
对于 ax+by=c 的不定方程,设 r=gcd(a,b)
当 c%r!=0 时无整数解
当 c%r=0 时,将方程右边 *r/c 后转换为 ax+by=r 的形式
可以根据扩展欧几里得算法求得一组整数解 x0 , y0
而这只是转换后的方程的解,原方程的一组解应再 *c/r 转变回去
(如 2x+4y=4 转换为 2x+4y=2 后应再将解得的 x , y 乘上2)
则原方程解为 x1=x0*c/r , y1=x0*c/r
通解 x=x1+b/r*t , y=y1-a/r*t ,其中 t 为整数
证明:
将 x , y 带入方程得
ax+ab/r*t+by-ab/r*t=c
ax+by=c
此等式恒成立
得证
这里 b/r 与 a/r 为最小的系数,所以求得的解是最多最全面的
栗1(题目戳这里)
这道题求得就是最小解,所以只要输出(x % b + b) % b就可以啦
CODE:
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <cmath> using namespace std; void exgcd(int a, int b, int &x, int &y) { if(b == 0) x = 1, y = 0; else exgcd(b, a % b, y, x), y -= a / b * x; } int main() { int n, m; scanf("%d%d", &n, &m); int x, y; exgcd(n, m, x, y); printf("%d\n", (x+m)%m); return 0; }
练习
https://www.luogu.org/problemnew/show/P2613
POJ 1061 http://poj.org/problem?id=1061
POJ 2115 http://poj.org/problem?id=2115
POJ 2142 http://poj.org/problem?id=2142
UVA 10090 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1031
http://codevs.cn/problem/1213/

浙公网安备 33010602011771号