『 exgcd 』 学习笔记
前言
寒假里花了一点时间在 B 栈自学了一点初等数论。根本不会。
感觉这个韩 ls 讲的挺好的。
没想到编程这么快也开始接触数论了。
直接看这个 \(\mathfrak{blog}\) 就好了。
正文
exgcd 其实是解决这样一个不定方程 \(ax+by=c\) 的,当然这个不定方程等价于 \(ax \equiv c \pmod p\) 。(很显然)
看到这里,你想到了什么?对,我们小学二年级就学过的 Bezout 定理(译作裴蜀定理或贝祖定理)。
Bezout 定理:若 \(a,b \in Z\), 则一定存在一对整数 \(x,y\) 满足
证明:
不妨将上式记为 \((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;
}

浙公网安备 33010602011771号