欧几里得与扩展
2018-06-17 08:36
183 查看
欧几里得:
gcd递归定义:对于任意正整数b,gcd(a,b)= gcd(b,a mod b)。
证明:
代码实现:
gcd 比较简单,接下来才是重头戏 --- 扩展。
扩展欧几里得:
这东西看似没啥用,实际其应用范围很广(逆元,不定方程...)。
现在我们有这样一个问题:
求解不定方程 ax + by = gcd(a,b).(假设 a >= b ).
设(xo,yo)是不定方程 ax+by=m 的一组解,(a,b)=g,那么全部解为
(xo+(b/g)t , yo - (a/g)t),其中 t 为所有整数.
模板代码:
习题练习:
NOIP 2012 同余方程
求关于 x 的同余方程ax ≡ 1(mod b) 即求解 ax + by = 1 中的 x 值,注意题目要求 正整数。
不是模板,胜似模板。
代码:
作者:RMY
出处:https://www.cnblogs.com/rmy020718/p/9192002.html
gcd递归定义:对于任意正整数b,gcd(a,b)= gcd(b,a mod b)。
证明:
只需要证明上面两者能相互整除。 设gcd(a,b)= d,所以d | a 且 d | b。由带余除法可以得出: a mod b = a - qb。其中 q = └a / b┘.所以 a mod b 是a 和 b的一个线性方程组合, 所以d |a mod b。又因为 d | b,所以 d | gcd(b,a mod b),即gcd(a,b)|gcd(b,a mod b)。 证明gcd(b,a mod b)|gcd(a,b)和上述过程几乎一样。
代码实现:
#include <iostream> #include <cstdio> using namespace std; int a,b; int gcd(int a,int b) { if(a<b)swap(a,b); //此处注意,why?仔细想想。 return a%b==0?b:gcd(b,a%b); } int main() { scanf("%d%d",&a,&b); printf("%d",gcd(a,b)); }
gcd 比较简单,接下来才是重头戏 --- 扩展。
扩展欧几里得:
这东西看似没啥用,实际其应用范围很广(逆元,不定方程...)。
现在我们有这样一个问题:
求解不定方程 ax + by = gcd(a,b).(假设 a >= b ).
当 b=0 时有 gcd(a,b)=a,此时 x=1,y=0 当 b 不为 0 时,根据 GCD 递归定理 gcd(a,b)=gcd(b, a mod b) 可得 ax+ by=gcd(a, b)=gcd(b, a mod b)=bx′ +(a mod b)y′ 即 ax+by=bx′+(a mod b)y′ = bx′+(a−b)×⌊a/b⌋y′ 移项得 ax+by=bx′+(a mod b)y=ay'+b(x-⌊a/b⌋y) 所以x=y',y=x'-⌊ a/b ⌋y'.
设(xo,yo)是不定方程 ax+by=m 的一组解,(a,b)=g,那么全部解为
(xo+(b/g)t , yo - (a/g)t),其中 t 为所有整数.
模板代码:
#include <cstdio> int exgcd(int a, int b, int &x, int &y) //非递归版 { int d; if (!b) x = 1, y = 0, d = a; else { d = exgcd(b, a % b, y, x); y -= (a / b) * x; } return d; } int exgcd(int a, int b, int &x, int &y) //递归版 { int d; return !b ? (x = 1, y = 0, a) : (d = exgcd(b, a % b, y, x), y -= (a / b) * x, d); } int main() { int a, b, x, y; scanf ("%d%d", &a, &b); printf("%d\n", exgcd(a, b, x, y)); printf("%d %d\n", x, y); }
习题练习:
NOIP 2012 同余方程
求关于 x 的同余方程ax ≡ 1(mod b) 即求解 ax + by = 1 中的 x 值,注意题目要求 正整数。
不是模板,胜似模板。
代码:
#include <cstdio> int exgcd(int a, int b, int &x, int &y) { int d; return !b ? (x = 1, y = 0, a) : (d = exgcd(b, a % b, y, x), y -= (a / b) * x, d); } int main() { int a, b, x, y; scanf ("%d%d", &a, &b); exgcd(a, b, x, y); int k=(0-x) /b; x=x+k*b; while(x<0){ x+=b; } //处理负数 printf("%d", x); }
作者:RMY
出处:https://www.cnblogs.com/rmy020718/p/9192002.html
相关文章推荐
- 数论基础(欧几里得,扩展欧几里得,逆元,斯特林)
- poj 1601 青蛙的约会 扩展欧几里得定理应用
- 校赛 倒咖啡 扩展欧几里得
- hdu 1573 A/B (扩展欧几里得)
- Ural 1286. Starship Travel (扩展欧几里得)
- 【POJ】【P1061】【青蛙的约会】【题解】【扩展欧几里得】
- 当我真正理解了扩展欧几里得定理
- ☆ Codeforces 724C Ray Tracing 扩展欧几里得 + 计算几何
- POJ 2115 扩展欧几里得
- 再论扩展欧几里得—POJ 1061 青蛙约会
- HDU 2669 扩展欧几里得最小非负解
- 乘法逆元 (扩展欧几里得或费马小定理)
- 当我真正理解了扩展欧几里得定理
- 扩展欧几里得
- Codeforces Gym - 101158 I - Skinny Polygon (扩展欧几里得)
- POJ 1061 青蛙的约会 笔记——扩展欧几里得
- poj 1061 青蛙的约会(扩展欧几里得)
- hdu1576(同余模定理&&扩展欧几里得)
- 第八届蓝桥杯 包子凑数(动态规划/完全背包+扩展欧几里得)
- poj 1061 青蛙的约会 ——扩展欧几里得