今天学习了拓展欧几里得,你不是会吗?
很多题解对我来说啃起来有难度,我在这里写一下自己的理解吧。
(所以下面每句话都是对我来说的)
(Part;1).
欧几里得算法。
一行了事,没大问题。
(Code):
int gcd(int a, int b){return b==0?a:gcd(b,a%b);}
相关定理:
挺有用的。
(Part;2).
裴蜀定理。
不定方程
有整数解的充分条件是:
很简单,设(a=k_1gcd(a,b),b=k_2gcd(a,b)),
左边(=(k_1x+k_2y)gcd(a,b)=)右边,存在解。
得证。
例题:P4549 【模板】裴蜀定理
裴蜀定理对多元不定方程仍成立。
(Part;3).
不定方程。
考虑有解的不定方程:
的一组解。
运用裴蜀定理,两边同时除以(gcd(a,b)),假设为:
同时除以(c'),得:
令(x'=dfrac{x}{c'},y'=b'dfrac{y}{c'}),方程化为:
可以跑扩欧了。
等一下,扩欧咋跑?
(Part;4).
拓展欧几里得。
求解方程:
或是
找个(y)值,使得(ax=by+1),显然(ax-by=1),这里令(yleqslant0),得:
就是上式了。
显然(a,b)互质。
我们令(a_1=b,b_1=(a;mod;b)),得一新方程:
我们的任务就是找这两个方程的解了。
由取模定义:
(a;mod;b=a-bleftlfloordfrac{a}{b}
ight
floor),可得:
整理一下可知:
那么原方程的解为:
那么(x_1,y_1)怎么求呢?
发现可以递归,最后会出现:
如果是求逆元,记得处理负数。
下面放上板子题代码:
(Code):
void exgcd(ll a,ll b)
{
if(b==0)
{
x=1,y=0;
return;
}
exgcd(b,a%b);
ll t=x;
x=y;
y=t-a/b*y;
}
int main()
{
ll a,b;
cin>>a>>b;
exgcd(a,b);
x=(x+b)%b;
cout<<x;
return 0;
}
(Part;5).
不定方程(进阶)。
上面说过一些,不过这里是找通解。
有个结论:
证明很费解:
发现只需证(ax_t+by_t=1)即可。
若成立
左边=(a(x_0+b't)+b(y_0-a't)=ax_0+by_0+ab't+a'bt=1+dfrac{abt}{gcd(a,b)}-dfrac{abt}{gcd(a,b)}=1)=右边。
得证。
(Part;6).
关于(x,y)的最小(大)整数解。
对于(x),就是个碾转相除嘛,求出的特解(x)一定是:
对(b')取模即得(x_{min}),
其实是满足:
的。
那么解的数量:
(加上两边)
这些同理于(y)。
就这些了。
(Code):
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
long long x,y;
long long gcd(long long a,long long b){return b==0?a:gcd(b,a%b);}
void exgcd(long long a,long long b)
{
if(b==0)
{
x=1,y=0;
return;
}
exgcd(b,a%b);
long long t=x;
x=y;
y=t-a/b*y;
}
long long t,a,b,c,g,minx,miny,maxx,maxy,num;
int main()
{
scanf("%lld",&t);
while(t--)
{
scanf("%lld%lld%lld",&a,&b,&c);
g=gcd(a,b);
if(c%g)
{
printf("-1
");
continue;
}
a/=g,b/=g,c/=g;
exgcd(a,b);
x*=c,y*=c;
minx=(x%b+b)%b;
if(!minx) minx+=b;
miny=(y%a+a)%a;
if(!miny) miny+=a;
maxx=(c-(b*miny))/a;
maxy=(c-(a*minx))/b;
num=(maxx-minx)/b+1;
if(num) printf("%lld %lld %lld %lld %lld
",num,minx,miny,maxx,maxy);
else printf("%lld %lld
",minx,miny);
}
return 0;
}
乱用(long;long)。
有些地方还不够详细,以后慢慢补吧(第三次复习?)