Miraclys

一言(ヒトコト)

扩展欧几里得

考虑问题求\(\ ax\equiv 1\pmod{b}\)的最小整数解,其中\(2 \leqslant a,b \leqslant 2000000000\)
\(\\\)
数据范围这么大我们肯定不能枚举,考虑别的方法。
\(\\\)
发现问题可以转化为:求\(ax_0+by_0=1\)的最小整数解\(x_0\)(此时\(y\)应该是负的)。
我们另写一个式子:\(bx_1 + (a-\lfloor \frac{a}{b} \rfloor)y_1 = 1\),整理下这个式子,得到\(ay_1+b\left( x_1- \lfloor \frac{a}{b}y_1\rfloor \right)=1\)
\(\\\)
这两个式子对应相等,我们可以得到关系:\(x_0 = y_1, y_0=x_1 - \lfloor \frac{a}{b}\rfloor y_1\),得到第二个式子,我们就是运用辗转相除的结果来变成系数,所以在\(log\)复杂度下我们会得到\(a_nx_n + b \times 0 = 1\),因为由裴属定理,这个不定方程要有解,则\(\gcd(a,b) | 1\),所以只能\(\gcd(a,b)=1\),所以最后\(a_n\)必定为1(我们由辗转相除来的),此时我们可以直接取\(x_n=\frac{1}{a_n}=1,y_n=0\),然后回代即可。
\(\\\)
注意最后我们要得到最小正整数解,我们通过这个方式得到的不一定是正数,可以通过\(x_0=((x_0\mod b)+b)\mod b\)来解决问题。因为当\(x_0<0\)时,\(x_0\mod b\)会结果为\(-\left( -x_0\mod b \right)\),所以这样就可以得到一个大于\(-b\)的负数,再加\(b\)即可得到最小的正数,如果\(x_0\)为正数,那么\(+b\)\(\mod b\)没有影响。
\(\\\)

using namespace std;

int x0, yy0;

inline int read() {
	int x = 0, f = 1;
	char c = getchar();
	while (!isdigit(c)) {
		if (c == '-') f = -1;
		c = getchar();
	}
	while (isdigit(c)) x = x * 10 + c - '0', c = getchar();
	return x * f;
}

inline void exgcd(int a, int b) {
	if (b == 0) {
		x0 = 1, yy0 = 0;
		return ;
	}
	exgcd(b, a % b);
	int temp = x0;
	x0 = yy0;
	yy0 = temp - (a / b) * yy0;
	return ;
}

int main() {
	int a, b;
	a = read(), b = read();
	exgcd(a, b);
	x0 = (x0 % b + b) % b;
	printf("%d", x0);
	return 0;
} 
posted @ 2022-09-18 20:12  Miraclys  阅读(17)  评论(0编辑  收藏  举报

关于本博客样式

部分创意和图片借鉴了

BNDong

的博客,在此感谢