洛谷P5656 【模板】二元一次不定方程 (exgcd) 题解
题目链接:P5656 【模板】二元一次不定方程 (exgcd)
题意:给定不定方程
a x + b y = c ax+by=c ax+by=c
若该方程无整数解,输出 − 1 -1 −1。
若该方程有整数解,且有正整数解,则输出其正整数解的数量,所有正整数解中 x x x 的最小值,所有正整数解中 y y y 的最小值,所有正整数解中 x x x 的最大值,以及所有正整数解中 y y y 的最大值。
若方程有整数解,但没有正整数解,你需要输出所有整数解中 x x x 的最小正整数值, y y y 的最小正整数值。正整数解即为 x , y x, y x,y 均为正整数的解, 0 \boldsymbol{0} 0 不是正整数。
整数解即为 x , y x,y x,y 均为整数的解。
x x x 的最小正整数值即所有 x x x 为正整数的整数解中 x x x 的最小值, y y y 同理。1 ≤ a , b , c ≤ 1 0 9 1\le a,b,c\le 10^9 1≤a,b,c≤109
根据裴蜀定理,
对于 x , y x,y x,y 的二元一次不定方程 a x + b y = c ax+by=c ax+by=c ,其有解的充要条件为 gcd ( a , b ) ∣ c \gcd(a,b) \mid c gcd(a,b)∣c
可知方程无解当且仅当 gcd ( a , b ) ∤ c \gcd(a,b) \nmid c gcd(a,b)∤c
那么有解的时候,我们可以用扩展欧几里德算法求出一组特解
即
x
′
,
y
′
x^{\prime},y^{\prime}
x′,y′ 满足
a
x
′
+
b
y
′
=
gcd
(
a
,
b
)
ax^{\prime}+by^{\prime}=\gcd(a,b)
ax′+by′=gcd(a,b)
考虑转化为原方程的一组特解。令 d = gcd ( a , b ) d=\gcd(a,b) d=gcd(a,b)
则特解
x
0
=
x
′
×
c
d
,
y
0
=
y
′
×
c
d
x_0=x^{\prime}\times \dfrac{c}{d},y_0 = y' \times \dfrac{c}{d}
x0=x′×dc,y0=y′×dc 满足
a
x
0
+
b
y
0
=
c
ax_0 + by_0 = c
ax0+by0=c
此时的
x
0
,
y
0
x_0,y_0
x0,y0 就是一个平凡的解,考虑转化为更有价值的解
考虑增大 x 0 x_0 x0 为 x 0 + p x_0+p x0+p ,则 y 0 y_0 y0 需减小至 y 0 − q y_0-q y0−q
故
{
a
×
(
x
0
+
p
)
+
b
×
(
y
0
−
q
)
=
c
a
x
0
+
b
y
0
=
c
\begin{cases} a\times(x_0+p)+b\times(y_0-q) = c\\\\ ax_0 + b y_0 = c \end{cases}
⎩⎪⎨⎪⎧a×(x0+p)+b×(y0−q)=cax0+by0=c
可得
p
=
b
q
a
p =\dfrac{bq}{a}
p=abq
可以发现这样的解有无数个,我们只要找到一个最小正整数解即可(即 p , q ∈ Z + p,q\in \Z_+ p,q∈Z+ 且 p , q p,q p,q 尽可能小)
∵ a ∣ b q , b ∣ b q \because a\mid bq,b\mid bq ∵a∣bq,b∣bq
∴ ( b q ) min = lcm ( a , b ) = a b gcd ( a , b ) \therefore (bq)_{\min}=\operatorname{lcm}(a,b) = \dfrac{ab}{\gcd(a,b)} ∴(bq)min=lcm(a,b)=gcd(a,b)ab
即
{
p
min
=
b
d
q
min
=
a
d
\begin{aligned}\begin{cases} p_{\min}&=\dfrac{b}{d}\\ \\ q_{\min}&=\dfrac{a}{d} \end{cases}\end{aligned}
⎩⎪⎪⎨⎪⎪⎧pminqmin=db=da
于是我们尝试将
x
0
x_0
x0 调至最小正整数(
y
0
y_0
y0 同时也会改变 )
即找到一个最小的整数 k k k 使得 x 0 + k p ≥ 1 x_0 + kp \ge 1 x0+kp≥1
则
k
=
⌈
1
−
x
0
p
⌉
k= \left\lceil{\dfrac{1-x_0}{p}}\right\rceil
k=⌈p1−x0⌉
然后将
x
0
x_0
x0 变为
x
0
+
k
p
x_0 + kp
x0+kp 即可,此时
y
0
y_0
y0 变化为
y
0
−
q
k
y_0-qk
y0−qk
若此时 y 0 > 0 y_0 > 0 y0>0 ,则存在正整数解
-
正整数解的个数:使 y 0 y_0 y0 不停地减 q q q 就是所有可行正整数解,故答案为 ⌊ y 0 − 1 q ⌋ + 1 \left\lfloor{\dfrac{y_0-1}{q}}\right\rfloor+1 ⌊qy0−1⌋+1
-
x x x 的最小正整数值: x 0 x_0 x0
-
y y y 的最小正整数值:使 y y y 不停地减 q q q ,最小的那个正整数就是答案,即 ( y 0 − 1 ) m o d q + 1 (y_0-1)\bmod q + 1 (y0−1)modq+1
-
x x x 的最大正整数值: y y y 最小时 x x x 最大
-
y y y 的最大正整数值: y 0 y_0 y0
若此时 y 0 ≤ 0 y_0 \le 0 y0≤0 ,则仅存在整数解
- x x x 的最小正整数值: x 0 x_0 x0
- y y y 的最小正整数值:构造 y 0 + k ′ q ≥ 1 y_0+k'q \ge 1 y0+k′q≥1 ,易知 k ′ = ⌈ 1 − y 0 q ⌉ k^{\prime} = \left\lceil{\dfrac{1-y_0}{q}}\right\rceil k′=⌈q1−y0⌉ ,故答案为 y 0 + q × ⌈ 1 − y 0 q ⌉ y_0+q\times \left\lceil{\dfrac{1-y_0}{q}}\right\rceil y0+q×⌈q1−y0⌉
据说要开
long long
\text{long long}
long long ,反正我#define int long long
丝毫不慌(逃
主要代码如下(省略了快读和多组数据)
#define int long long
int exgcd(int a,int b,int &x,int &y)
{
int d=a;
if(!b)x=1,y=0;
else d=exgcd(b,a%b,y,x),y-=a/b*x;
return d;
}
void solve()
{
int a,b,c,x,y;
read(a);read(b);read(c);
int d=exgcd(a,b,x,y);
if(c%d!=0){puts("-1");return;}
x*=c/d;y*=c/d;
int p=b/d,q=a/d,k;
k=ceil((1.0-x)/p),x+=p*k,y-=q*k;
if(y>0)
{
write((y-1)/q+1); pc(' ');
write(x); pc(' ');
write((y-1)%q+1); pc(' ');
write(x+(y-1)/q*p);pc(' ');
write(y); pc(' ');
}else
{
write(x); pc(' ');
write(y+q*(int)ceil((1.0-y)/q));pc(' ');
}
pc('\n');
}
参考文献
[1] https://www.luogu.com.cn/blog/McHf/p5656-exgcd
转载请说明出处