……

扩欧复习课

很多题解对我来说啃起来有难度,我在这里写一下自己的理解吧。

\(Part\;1\).

欧几里得算法。
一行了事,没大问题。

\(Code\):

int gcd(int a, int b){return b==0?a:gcd(b,a%b);}

相关定理:

\[\gcd(a,b)=\dfrac{ab}{\operatorname{lcm}(a,b)} \]

挺有用的。

\(Part\;2\).

裴蜀定理。
不定方程

\[ax+by=c \]

有整数解的充分条件是:

\[\gcd(a,b)|c \]

很简单,设 \(a=k_1\gcd(a,b),b=k_2\gcd(a,b)\)
左边 \(=(k_1x+k_2y)\gcd(a,b)=\) 右边,存在解。
得证。
例题:P4549 【模板】裴蜀定理
裴蜀定理对多元不定方程仍成立。

\(Part\;3\).

不定方程。
考虑有解的不定方程:

\[ax+by=c \]

的一组解。
运用裴蜀定理,两边同时除以 \(\gcd(a,b)\),假设为:

\[a'x+b'y=c' \]

同时除以 \(c'\),得:

\[a'\dfrac{x}{c'}+b'\dfrac{y}{c'}=1 \]

\(x'=\dfrac{x}{c'},y'=b'\dfrac{y}{c'}\),方程化为:

\[a'x'+b'y'=1 \]

可以跑拓欧了。
等一下,拓欧咋跑?

\(Part\;4\).

拓展欧几里得。
求解方程:

\[ax+by=1 \]

或是

\[ax\equiv1\pmod{b} \]

找个 \(y\) 值,使得 \(ax=by+1\),显然 \(ax-by=1\) ,这里令 \(y\leqslant0\),得:

\[ax+by=1 \]

就是上式了。
显然 \(a,b\) 互质。
我们令 \(a_1=b,b_1=(a\bmod b)\),得一新方程:

\[a_1x_1+b_1y_1=1 \]

我们的任务就是找这两个方程的解了。
由取模定义:
\(a\bmod b=a-b\left\lfloor\dfrac{a}{b}\right\rfloor\),可得:

\[bx_1+(a-b\left\lfloor\dfrac{a}{b}\right\rfloor)y_1=1=ax+by \]

整理一下可知:

\[ay_1+b(x_1-y_1\left\lfloor\dfrac{a}{b}\right\rfloor)=ax+by \]

那么原方程的解为:

\[x=y_1,y=x_1-y_1\left\lfloor\dfrac{a}{b}\right\rfloor \]

那么 \(x_1,y_1\) 怎么求呢?
发现可以递归,最后会出现:

\[x=1,b_n=0,a_n=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\).

不定方程(进阶)。
上面说过一些,不过这里是找通解。

有个结论:

\[\begin{cases}x_t=x_0+b't\\y_t=y_0-a't\end{cases} \]

证明很费解:
发现只需证 \(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\) 一定是:

\[x=x_{min}+b'k \]

\(b'\) 取模即得 \(x_{min}\)
其实是满足:

\[b'y_{min}+a'x_{max}=c' \]

的。
那么解的数量:

\[sum=\dfrac{x_{max}-x_{min}}{b'}+1 \]

(加上两边)
这些同理于 \(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\n");
			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\n",num,minx,miny,maxx,maxy);
		else printf("%lld %lld\n",minx,miny);
	}
	return 0;
}

乱用 long long ......

posted @ 2020-02-20 07:55  童话镇里的星河  阅读(201)  评论(0编辑  收藏  举报