[Acwing蓝桥杯数学知识] 扩展欧几里得线性同余方程
作者:互联网
扩展欧几里得
用于求解方程 ax+by=gcd(a,b)的解
当 b=0时 ax+by=aax+by=a 故而 x=1,y=0x=1,y=0
当 b≠0 时因为gcd(a,b)=gcd(b,a%b)
而bx′+(a%b)y′=gcd(b,a%b)
bx′+(a−⌊a/b⌋∗b)y′=gcd(b,a%b)
ay′+b(x′−⌊a/b⌋∗y′)=gcd(b,a%b)=gcd(a,b)
故而x=y′,y=x′−⌊a/b⌋∗y′
因此可以采取递归算法 先求出下一层的x′和y′再利用上述公式回代即可
线性同余方程
已知 ax+by=z ( z是d的倍数 )
如果z不是d的倍数一般表示无解
这时要想用扩展欧几里得的结果
就要将等式两边同时*z/d
即x*=z/d,y*z/d;
线性同余方程一定能求出一个解(x0,y0)
且满足:
就是任意的x和y都可以用x0和y0表示出来
要求最小的x值就是 x0 MOD(b/d);
一般就是先将x扩大后 先将b除以d 然后直接MOD b就是结果
注意x一般要的是正数 则要取正数x=(x%b+b)%b;
有两个例题:1301. C 循环 - AcWing题库 ,1299. 五指山 - AcWing题库;
第一个题的代码:
1 /* 2 线性同余方程 3 4 由题意得 5 (A+C*x)mod2^k=B 6 变形:A+C*x-2^k*y=B 7 即 C*x-2^k*y=B-A 8 ax+by=d 9 10 */ 11 12 #include <bits/stdc++.h> 13 14 using namespace std; 15 typedef long long LL; 16 17 LL exgcd(LL a,LL b,LL &x,LL &y) 18 { 19 if(!b) 20 { 21 x=1,y=0; 22 return a; 23 } 24 LL d=exgcd(b,a%b,y,x); 25 y-=a/b*x; 26 return d; 27 } 28 29 int main() 30 { 31 LL a,b,c,k; 32 while(cin>>a>>b>>c>>k,a,b,c,k) 33 { 34 LL x,y; 35 k=1LL<<k; 36 LL d=exgcd(c,k,x,y); 37 if((b-a)%d)puts("FOREVER"); 38 else 39 { 40 x*=(b-a)/d; 41 k/=d; 42 printf("%lld\n",(x%k+k)%k); 43 } 44 } 45 return 0; 46 }View Code
第二个题的代码:
/*裴蜀定理,算法:扩展欧几里得算法 传送门https://www.acwing.com/problem/content/879/ ax+by=d a x +by=exgcd 实际上应该为 n*(-x)+dy=y-x; y-x如果不能整除exgcd那么无解 如果可以 那么两边同时除以(y-x)/exgcd x->a y->b 求y */ #include <bits/stdc++.h> using namespace std; typedef long long LL; LL exgcd(LL a,LL b,LL &x,LL &y) { if(!b) { x=1,y=0; return a; } LL d=exgcd(b,a%b,y,x); y-=a/b*x; return d; } int main() { int T; cin>>T; while(T--) { LL a,b,x,y,d,n; scanf("%lld%lld%lld%lld",&n,&d,&x,&y); LL gcd=exgcd(n,d,a,b); if((y-x)%gcd)puts("Impossible"); else { b*=(y-x)/gcd; n/=gcd; printf("%lld\n", (b % n + n) % n); } } return 0; }View Code
两个题都是线性同余方程的应用:
方程的转化和求解。
end!!!
标签:a%,gcd,LL,exgcd,蓝桥,return,同余,Acwing 来源: https://www.cnblogs.com/qinmo/p/16079826.html