轻量级前端框架助力开发者提升项目效率与性能
544
2022-11-09
重拾拓展欧几里得 & 简单不定方程
过一段时间不用拓展欧几里得就把代码忘了,这是没有深入理解的恶果啊。写下一文,回忆回忆基础而重要的拓展欧几里得
拓展欧几里得函数 ex_gcd() 可以用于求解逆元,不定方程,同余式(随便也能把模与被模数的最大公约数求出来)。
贴上代码:
void ex_gcd(LL a,LL b,LL &d,LL &x,LL &y){ if(b==0){ d=a; x=1; y=0; return ; } ex_gcd(b,a%b,d,x,y); LL t=x; x=y; y=t-a/b*y;}
工作原理:
例如:number=225 mod=21
辗转相减:
225-21*10=15
21-15*1=6
15-6*2=3
6-3*2=0
最大公约数即是: 3
求解225模21的逆元:
当ex_gcd()递归终止时,两个数字的最大公约数被找到,两个数字化简后进行下面的回溯运算:
X是上一次的Y,Y是上一次的X减去(a/b)和上一次Y的乘积。
得到的x就是相关逆元(两个数字互质时的逆元)
75*3=225%7=1
中间值:
18435915192532888 225 21
18435915192532888 21 15
18435915192532888 15 6
18435915192532888 6 3
18435915192532888 3 0
3 0 1 6 3
3 1 -2 15 6
3 -2 3 21 15
3 3 -32 225 21
Process returned 0 (0x0) execution time : 0.391 s
Press any key to continue.
关于实验的代码:
void ex_gcd(LL a,LL b,LL &d,LL &x,LL &y){ cout< ex_gcd()在求解逆元和方面就不说了,下面聊一聊它在不定方程上的应用: 关于不定方程: 当然,实际写程序中更方便的做法是: 在用拓展欧几里得时直接带入x0,y0就行,最后X0=c/d*x0 Y0=c/d*y0 相关例题: The Balance 求出x和y的绝对值,且|x|+|y| min,|ax|+|by| min 分析:利用ex_gcd()求得一组解x0,y0,得出通解的表达式:x=x0-Bt y=y0+At |x|+|y|=|x0-Bt|+|y0+At| 将最开始的a,b设成a 小负大正 |x0-Bt|是一个凹函数(t<0 and t>=0) |y0+At| 是一个增函数 且因为B=b/d A=a/d 所以较小的速度大于增大的速率。所以整体是一个凹函数。而那个凹点就是使得x0-Bt=0的t值。求出它并在其周围几个点枚举一下就能得到答案。(距离设为2能AC,但是设为1就不行了 T_T) #include SGU 106 The equation [y1,y2]内解的个数。 相关知识: 拓展欧几里的求解不定方程:ax+by=c 假设x1<=x2, y1<=y2 当a=0,b=0时,如果c=0 解的个数是:(x2-x1+1)(y2-y1+1) ; 如果c!=0,解的个数是0 当 a=0
,
b!=0时,如果c%b=0,且-c/
b在y的要求范围内,那么解的个数是x2-x1+1
;
如果c%b!
=
0,或
-c/b不
在y的要求范围内,那么解的个数是0 当 a!
=0,b
=0时
过程类似。 当a!=0,b!=0,进入不定方程的解决程序: 方程转化成 ax+by=-c 拓展欧几里的a,b参数是正整数,所以将其进行相应的设置。 if(a<0) [x1,x2] --> [-x2,x1] if(b<0) [y1,y2] --> [-y2,y1] 分开讨论: x1, y1 确定下界 x2, y2 确定上界 图变成这个样子了: 所以,这样确定上下界: #include
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~