『 exgcd 』 学习笔记

前言

寒假里花了一点时间在 B 栈自学了一点初等数论。根本不会。

感觉这个韩 ls 讲的挺好的。

没想到编程这么快也开始接触数论了。

直接看这个 \(\mathfrak{blog}\) 就好了。

正文

exgcd 其实是解决这样一个不定方程 \(ax+by=c\) 的,当然这个不定方程等价于 \(ax \equiv c \pmod p\) 。(很显然)

看到这里,你想到了什么?对,我们小学二年级就学过的 Bezout 定理(译作裴蜀定理或贝祖定理)。

Bezout 定理:若 \(a,b \in Z\), 则一定存在一对整数 \(x,y\) 满足

\[ax+by=\gcd(a,b) \]

证明

不妨将上式记为 \((1)\) ,记 \(d=\gcd(a,b)\)

\(a,b\) 中有一数为 \(0\),假设 \(a=0\), 则 \(d=b\) 。此时 \((1)\) 可化为 \(by=m\) 。它有整数解,当且仅当 \(m\)\(b\) 的倍数。

\(\because\) \(x\) 可以是任意整数

\(\therefore\) 定理成立。

\(a,b\) 都不为 \(0\)

\(S\)\(a+b\) 的最小正值(最小数定理)。

由带余除法: \(a=q\times S+r\)

\(\therefore\) \(r=a-q\times S=a-q(ax+by)=a(1-q\times x)-b(q\times y)\)

\(\because\) \(q,x,y \in Z\) \(\therefore\) \(r\) 也是 \((a,b)\) 的线性组合。

\(\because\) \(S\)\(ax+by\) 的最小值 \(\therefore\) \(r=0\) \(\therefore\) \(S|a\)

同理可得: \(S|b\)

\(\therefore\) \(S|d\)

\(\because\) \(d|a,d|b\) \(\therefore\) \(d|(ax+by)\)

\(\therefore\) \(d|S\)

\(\therefore\) \(S=d\) \(\blacksquare\)

当然也可以用欧几里得算法去证。

由 Bezout 定理我们知道 \(ax+by=c\)\(\gcd(a,b)|c\)

然后,很显然 \(\gcd(a,b)=\gcd(b,a \bmod b)\)

因而,我们可以得出 exgcd 的模板(草率)(求关于 \(x\) 的方程 \(ax \equiv 1 \pmod b\) 的最小正整数解):

#include<bits/stdc++.h>
#define FOR(i,j,k)  for(int i=(j);i<=(k);i++)
using namespace std;
long long a,b,x,y;
inline long long read()
{
	long long x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	return x*f;
}
void exgcd(long long a,long long b)
{
	if(!b)
	{
		x=1,y=0;
		return ;
	}
	exgcd(b,a%b);
	long long tx=x;
	x=y,y=tx-a/b*y;
}
int main()
{
	a=read(),b=read();
	exgcd(a,b);
	x=(x%b+b)%b;
	printf("%lld\n",x);
	return 0;
}

posted @ 2021-04-05 10:24  LJC001151  阅读(106)  评论(0)    收藏  举报