【模板】二元一次不定方程 exgcd

posted on 2022-09-17 15:59:26 | under 模板 | source

code

LL mod(LL x,LL m){return(x%m+m)%m;}
LL exgcd(LL a,LL b,LL c,LL& x,LL& y){
	if(!b) return x=c/a,y=0,a;
	LL res=exgcd(b,a%b,c,y,x);
	return y-=a/b*x,res;
}
LL solve(LL a,LL b,LL c){
	LL x,y,d=exgcd(a,b,c,x,y);
	return c%d==0?mod(x,b/d):-1;
}
template <class T>
tuple<T, T, T> exgcd(T a, T b, T c) {
    if (!b) return {c / a, 0, a};
    auto [x, y, d] = exgcd(b, a % b, c);
    return {y, x - a / b * y, d};
}
template <class T>
T solveEquation(T a, T b, T c) { // get the vaild solution x of ax + by = c
    auto [x, y, d] = exgcd(a, b, c);
    auto mod = [](T x, T y) { return (x % y + y) % y; };
    return c % d == 0 ? mod(x, b / d) : -1;
}
template <class T>
T getInv(T a, T p) {
    return solveEquation(a, p, 1);
}

调用 solve(a,b,c) 能求得 \(ax+by=c\)\(x\) 的最小非负整数解,无解返回 \(-1\)

\(n\) 在模 \(P\) 意义下的逆元是 solve(n,P,1)

但是,为什么这样写对呢?

exgcd

我们想求的是这样一个东西的一组解 \((x,y)\)\(ax+by=\gcd(a,b)\)

回忆一下我们求 \(\gcd\) 的过程,我们用到了 \(\gcd(a,b)=\gcd(b,a\bmod b)\) 的性质。

将原方程的 \((a,b)\) 全部替换成 \((b,a\bmod b)\) 也应该成立:

\[bx+(a\bmod b)y=\gcd(b,a\bmod b). \]

取模的定义:\(a\bmod b=a-\left\lfloor\frac{a}{b}\right\rfloor\cdot b\)(下文 \(\left\lfloor\frac{a}{b}\right\rfloor\) 写作 \(a/b\)),代入:

\[\begin{aligned} bx+(a-(a/b)\cdot b)y&=\gcd(b,a\bmod b)\\ bx+ay-(a/b)\cdot by&=\gcd(b,a\bmod b)\\ ay+b(x-(a/b)\cdot y)&=\gcd(b,a\bmod b)\\ \end{aligned}\]

我们貌似看到了一组新的解 \((x'=y,y'=x-(a/b)\cdot y)\)。这就是 exgcd。将这个过程递归下去即可。

发现还有递归边界,此时 \(b=0\),原方程变为 \(ax=a\)\(a\) 是原来的 \(\gcd(a,b)\)),取 \((x=1,y=0)\)\(y\) 可以是任何数,但一般取 \(0\)),即为递归边界。

LL exgcd(LL a,LL b,LL& x,LL& y){
	if(!b) return x=1,y=0,a;
	LL res=exgcd(b,a%b,y,x);
	return y-=a/b*x,res;
}
exgcd :: Integral a => (a, a) -> (a, a)
exgcd (a, 0) = (1, 0)
exgcd (a, b) = let (x, y) = exgcd (b, a `mod` b) in (y, x - (a `div` b) * y)

继续

exgcd 可以求出形如 \(ax+by=\gcd(a,b)\) 的一组整数特解 \((x_0,y_0)\)

由裴蜀定理得,如果 \(\gcd(a,b)\not\mid c\) 那么直接跑路。

否则,等式两边同时乘 \(\frac{c}{\gcd(a,b)}\),得到原方程 \(ax+by=c\) 的特解 \((x_1=\frac{c}{\gcd(a,b)}\cdot x_0,y_1=\frac{c}{\gcd(a,b)}\cdot y_0)\)

考虑这么一个式子,它和原方程等价:

\[a(x_1+db)+b(y_1-da)=c \]

显然 \(d\) 可以取到 \(1/\gcd(a,b)\),所以得到任意一组解 \((x,y)\) 都满足:

\[\begin{cases} x=x_1+s\cdot\frac{b}{\gcd(a,b)},\\ y=y_1-s\cdot\frac{a}{\gcd(a,b)}.\\ \end{cases}\]

所以 \(x\) 的最小的正整数解是 \(x_1\bmod \frac{b}{\gcd(a,b)}\)。我们止步于此。

code-analysis

LL mod(LL x,LL m){return(x%m+m)%m;}
LL exgcd(LL a,LL b,LL c,LL& x,LL& y){
	if(!b) return x=c/a,y=0,a;
    //x=c/a,提前算好 x_1,这里 a 是 gcd
	LL res=exgcd(b,a%b,c,y,x);
	return y-=a/b*x,res;
}
LL solve(LL a,LL b,LL c){
	LL x,y,d=exgcd(a,b,c,x,y);
	return c%d==0?mod(x,b/d):-1;
    //先判无解,如果有解就模
}
posted @ 2022-11-06 19:17  caijianhong  阅读(71)  评论(0编辑  收藏  举报