数论小结
1. 扩展欧几里得
首先,根据辗转相除法,不难有:
\[\gcd(a,b)=\gcd(b,a\%b)
\]
关于扩展欧几里得算法,是解决线性方程:\(ax+by=c\) 当且仅当,\(\gcd(a,b)|c\) 有解
又因为,\(x,y\in\Z\),所以问题可以转化为,解线性方程:\(ax+by=\gcd(a,b)\) 这就是扩展欧几里得算法的初始条件
假设,我们有方程的一组解 \(x_0,y_0\), 则:
\[ax_0+by_0=\gcd(a,b)=\gcd(b,a\%b)\qquad(1)
\]
于是,构造新的线性方程与其解 \(x_1,y_1\),满足:
\[bx_1+(a\%b)y_1=\gcd(b,a\%b)\qquad(2)
\]
联立 \((1),(2)\) 式,我们有:
\[ax_0+by_0=\gcd(a,b)=\gcd(b,a\%b)=bx_1+(a\%b)y_1\\
=bx_1+(a-\lfloor a/b\rfloor\times b)y_1\\
=ay_1+b(x_1-\lfloor a/b\rfloor y_1)
\]
结论一:
\[\cases{
x_0\leftarrow y_1\\
y_0\leftarrow x_1-\lfloor a/b\rfloor y_1\\
}
\]
结论二:
\[\cases{
x_0\leftarrow y_1\\
y_0\leftarrow x_1\\
a\leftarrow b\\
b\leftarrow a\%b\\
\gcd(a,b)\leftarrow \gcd(b,a\%b)\\
}
\]
于是可以考虑设计递归或者迭代代码。
递归版本
int ex_gcd(int a, int b, int &x, int &y) {
if (b == 0) {
x = 1, y = 0;
return a;
}
int d = ex_gcd(b, a % b, y, x);// 注意:这里已经调换了x,y顺序
y -= (a / b) * x;
return d;
}
2. 乘法逆元(扩展欧几里得算法求解)
问题描述
求解 \(ax\equiv1\mod{n}\)
\[ax\equiv1\mod n\\
\iff ax+ny\equiv1\mod n
\]
当且仅当,\(\gcd(a,n)=1\) 有解,求解 \(ax+ny=1\) 使用扩展欧几里得算法
乘法逆元-代码
int inv(int a, int n) {
int x, y, d = ex_gcd(a, n, x, y);
if (d == 1) {
if (x % n <= 0)
return x % n + n;
else
return x % n;
}
return -1;
}