【模板】二元一次不定方程 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=cx 的最小非负整数解,无解返回 1

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

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

exgcd

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

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

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

bx+(amodb)y=gcd(b,amodb).

取模的定义:amodb=aabb(下文 ab 写作 a/b),代入:

bx+(a(a/b)b)y=gcd(b,amodb)bx+ay(a/b)by=gcd(b,amodb)ay+b(x(a/b)y)=gcd(b,amodb)

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

发现还有递归边界,此时 b=0,原方程变为 ax=aa 是原来的 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) 的一组整数特解 (x0,y0)

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

否则,等式两边同时乘 cgcd(a,b),得到原方程 ax+by=c 的特解 (x1=cgcd(a,b)x0,y1=cgcd(a,b)y0)

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

a(x1+db)+b(y1da)=c

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

{x=x1+sbgcd(a,b),y=y1sagcd(a,b).

所以 x 的最小的正整数解是 x1modbgcd(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 @   caijianhong  阅读(106)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示