裴蜀定理扩展欧几里得定理
裴蜀定理(又称贝祖定理)
理论
一定存在整数 x , y x, y x,y,满足 a x + b y = g c d ( a , b ) ax + by = gcd(a, b) ax+by=gcd(a,b)
例
4
x
+
6
y
=
2
4x + 6y = 2
4x+6y=2,有整数解
x
=
−
1
,
y
=
1
x = -1, y = 1
x=−1,y=1。
而
4
x
+
6
y
=
3
4x + 6y = 3
4x+6y=3,即
x
=
3
−
6
y
4
x = \frac{3 - 6y}{4}
x=43−6y 无整数解。
证明:
设取整数 x 0 , y 0 x_0, y_0 x0,y0 时, a x + b y ax + by ax+by 的最小正整数为 s s s
即 a x 0 + b y 0 = s ax_0 + by_0 = s ax0+by0=s
因 g c d ( a , b ) ∣ a x 0 gcd(a, b) \mid ax_0 gcd(a,b)∣ax0, g c d ( a , b ) ∣ b y 0 gcd(a, b) \mid by_0 gcd(a,b)∣by0,
故 g c d ( a , b ) ∣ s ⋯ ⋯ ( 1 ) gcd(a, b) \mid s \cdots\cdots (1) gcd(a,b)∣s⋯⋯(1)
设 a = q s + r ( 0 ≤ r < s ) a = qs + r (0 \leq r < s) a=qs+r(0≤r<s)
r = a − q s r = a - qs r=a−qs
= a − q ( a x 0 + b y 0 ) = a - q(ax_0 + by_0) =a−q(ax0+by0)
= a ( 1 − q x 0 ) + b ( − q y 0 ) = a(1 - qx_0) + b(-qy_0) =a(1−qx0)+b(−qy0)
= a x + b y = ax + by =ax+by
因 s s s 是最小正整数,故 r = 0 r = 0 r=0
所以 s ∣ a s \mid a s∣a,同理 s ∣ b s \mid b s∣b,
故 s ∣ g c d ( a , b ) ⋯ ⋯ ( 2 ) s \mid gcd(a, b) \cdots\cdots (2) s∣gcd(a,b)⋯⋯(2)由 ( 1 ) ( 2 ) (1)(2) (1)(2) 得 s = g c d ( a , b ) s = gcd(a, b) s=gcd(a,b)。证毕。
裴蜀定理推广
一定存在整数
x
,
y
x, y
x,y,满足
a
x
+
b
y
=
g
c
d
(
a
,
b
)
×
n
ax + by = gcd(a, b) \times n
ax+by=gcd(a,b)×n
例 4 x + 6 y = 8 4x + 6y = 8 4x+6y=8,有整数解 x = − 4 , y = 4 x = -4, y = 4 x=−4,y=4。
裴蜀定理再推广
一定存在整数
X
1
⋯
X
i
X_1 \cdots X_i
X1⋯Xi,满足
∑
i
=
1
n
A
i
X
i
=
g
c
d
(
A
1
,
A
2
,
⋯
,
A
n
)
\sum_{i = 1}^{n} A_iX_i = gcd(A_1, A_2, \cdots, A_n)
∑i=1nAiXi=gcd(A1,A2,⋯,An)
例 4 x 1 + 6 x 2 + 2 x 3 = 4 4x_1 + 6x_2 + 2x_3 = 4 4x1+6x2+2x3=4,有整数解 x 1 = 1 , x 2 = 0 , x 3 = 0 x_1 = 1, x_2 = 0, x_3 = 0 x1=1,x2=0,x3=0。
裴蜀定理扩展
a
x
+
b
y
=
n
ax + by = n
ax+by=n
结论:
- 若 n > a b − a − b n > ab - a - b n>ab−a−b,有解
- 若 n = 0 n = 0 n=0,有解
- 若 n < 0 n < 0 n<0,无解
- 若 a x + b y = n ax + by = n ax+by=n 有解,则 a x + b y = a b − a − b − n ax + by = ab - a - b - n ax+by=ab−a−b−n 无解
注意
欧几里得算法求 g c d ( a , b ) gcd(a, b) gcd(a,b)
如果代入负数,结果会返回负数
例: g c d ( 8 , − 4 ) = − 4 gcd(8, -4) = -4 gcd(8,−4)=−4
如果系数 A i A_i Ai 为负数,
求 g c d gcd gcd 时可代入其绝对值,
确保所求最大公约数为正数,
这样并不会影响解的存在。
例题
P4549 【模板】裴蜀定理
题目描述
给定一个包含
n
n
n 个元素的整数序列
A
A
A,记作
A
1
,
A
2
,
A
3
,
.
.
.
,
A
n
A_1,A_2,A_3,...,A_n
A1,A2,A3,...,An。
求另一个包含
n
n
n 个元素的待定整数序列
X
X
X,记
S
=
∑
i
=
1
n
A
i
×
X
i
S=\sum\limits_{i=1}^nA_i\times X_i
S=i=1∑nAi×Xi,使得
S
>
0
S>0
S>0 且
S
S
S 尽可能的小。
输入格式
第一行一个整数
n
n
n,表示序列元素个数。
第二行
n
n
n 个整数,表示序列
A
A
A。
输出格式
一行一个整数,表示
S
>
0
S>0
S>0 的前提下
S
S
S 的最小值。
输入输出样例 #1
输入 #1
2
4059 -1782
输出 #1
99
说明/提示
对于
100
%
100\%
100% 的数据,
1
≤
n
≤
20
1 \le n \le 20
1≤n≤20,
∣
A
i
∣
≤
1
0
5
|A_i| \le 10^5
∣Ai∣≤105,且
A
A
A 序列不全为
0
0
0。
#include<bits/stdc++.h>
using namespace std;
int gcd(int a, int b)
{
return b ? gcd(b, a % b) : a;
}
int main()
{
int n, ans;
cin >> n;
for (int i = 1; i <= n; i++)
{
int x;
cin >> x;
if (i == 1)
{
ans = abs(x);
}
else
{
ans = gcd(ans, abs(x));
}
}
cout << ans;
return 0;
}
买不到的数目
题目描述
小明开了一家糖果店。他别出心裁:把水果糖包成 4 颗一包和 7 颗一包的两种。糖果不能拆包卖。
小朋友来买糖的时候,他就用这两种包装来组合。当然有些糖果数目是无法组合出来的,比如要买 10 颗糖。
你可以用计算机测试一下,在这种包装情况下,最大不能买到的数量是 17。大于 17 的任何数字都可以用 4 和 7 组合出来。
本题的要求就是在已知两个包装的数量时,求最大不能组合出的数字。
输入描述
输入两个正整数,表示每种包装中糖的颗数(都不多于 1000 )。
输出描述
输出一个正整数,表示最大不能买到的糖数。
不需要考虑无解的情况
输入输出样例
示例
输入
4 7
输出
17
#include <iostream>
using namespace std;
int x, y;
int main()
{
cin >> x >> y;
cout << x * y - x - y << endl;
return 0;
}
扩展欧几里得算法
理论
问题1:
求 a x + b y = g c d ( a , b ) ax + by = gcd(a, b) ax+by=gcd(a,b) 的一组整数解
当
b
=
0
b = 0
b=0 时
a
x
+
b
y
=
a
ax + by = a
ax+by=a 故而
x
=
1
,
y
=
0
x = 1, y = 0
x=1,y=0
当
b
≠
0
b \neq 0
b=0 时
由欧几里得算法,
g
c
d
(
a
,
b
)
=
g
c
d
(
b
,
a
%
b
)
gcd(a, b) = gcd(b, a\%b)
gcd(a,b)=gcd(b,a%b)
由裴蜀定理,
g
c
d
(
a
,
b
)
=
a
x
+
b
y
gcd(a, b) = ax + by
gcd(a,b)=ax+by
g
c
d
(
b
,
a
%
b
)
=
b
x
1
+
(
a
%
b
)
y
1
gcd(b, a\%b) = bx_1 + (a\%b)y_1
gcd(b,a%b)=bx1+(a%b)y1
=
b
x
1
+
(
a
−
⌊
a
b
⌋
×
b
)
y
1
= bx_1 + (a - \lfloor\frac{a}{b}\rfloor\times b)y_1
=bx1+(a−⌊ba⌋×b)y1
=
a
y
1
+
b
(
x
1
−
a
b
y
1
)
= ay_1 + b(x_1 - \frac{a}{b}y_1)
=ay1+b(x1−bay1)
所以
x
=
y
1
x = y_1
x=y1,
y
=
x
1
−
a
b
y
1
y = x_1 - \frac{a}{b}y_1
y=x1−bay1
可以用递归算法,先求出下一层的
x
1
,
y
1
x_1, y_1
x1,y1,再回代到上一层,层层回代,可求特解
(
x
0
,
y
0
)
(x_0, y_0)
(x0,y0)
构造通解
{
x
=
x
0
+
b
g
c
d
(
a
,
b
)
∗
k
y
=
y
0
−
a
g
c
d
(
a
,
b
)
∗
k
\begin{cases} x = x_0 + \frac{b}{gcd(a, b)}*k \\ y = y_0 - \frac{a}{gcd(a, b)}*k \end{cases}
{x=x0+gcd(a,b)b∗ky=y0−gcd(a,b)a∗k (考虑
a
x
+
b
y
=
0
ax + by = 0
ax+by=0 构造)
例: 8 x + 6 y = 2 8x + 6y = 2 8x+6y=2,解: ( 1 , − 1 ) , ( 4 , − 5 ) , ( 7 , − 9 ) ⋯ (1, -1), (4, -5), (7, -9)\cdots (1,−1),(4,−5),(7,−9)⋯
//欧几里得算法
int gcd(int a, int b) {
if (b == 0) {
return 0;
}
return gcd(b, a % b);
}
int exgcd(int a, int b, int& x, int& y) {
if (b == 0) {
int x = 1, y = 0;
return a;
}
int x1, y1, d;
d = exgcd(b, a % b, x1, y1);
x = y1, y = x1 - a / b * y1;
return d;
}
问题2:
求不定方程 a x + b y = c ax + by = c ax+by=c 的一组整数解
- 若
g
c
d
(
a
,
b
)
∣
c
gcd(a, b) \mid c
gcd(a,b)∣c,则有整数解
- 先用扩欧算法求 a x + b y = g c d ( a , b ) ax + by = gcd(a, b) ax+by=gcd(a,b) 的解
- 再乘以 c / g c d ( a , b ) c / gcd(a, b) c/gcd(a,b),即得原方程的特解 ( x 0 , y 0 ) (x_0, y_0) (x0,y0)
- 例: 8 x + 6 y = 6 8x + 6y = 6 8x+6y=6,解得 x = 3 , y = − 3 x = 3, y = -3 x=3,y=−3
构造通解
{
x
=
x
0
+
b
g
c
d
(
a
,
b
)
∗
k
y
=
y
0
−
a
g
c
d
(
a
,
b
)
∗
k
\begin{cases} x = x_0 + \frac{b}{gcd(a, b)}*k \\ y = y_0 - \frac{a}{gcd(a, b)}*k \end{cases}
{x=x0+gcd(a,b)b∗ky=y0−gcd(a,b)a∗k (考虑
a
x
+
b
y
=
0
ax + by = 0
ax+by=0 构造)
- 若
g
c
d
(
a
,
b
)
∤
c
gcd(a, b) \nmid c
gcd(a,b)∤c,则无整数解。
- 例: 8 x + 6 y = 3 8x + 6y = 3 8x+6y=3, x = 3 − 6 y 8 x = \frac{3 - 6y}{8} x=83−6y
#include<bits/stdc++.h>
using namespace std;
int exgcd(int a, int b, int& x, int& y) {
if (b == 0) {
x = 1, y = 0;
return a;
}
int x1, y1, d;
d = exgcd(b, a % b, x1, y1);
x = y1;
y = x1 - a / b * y1;
return d;
}
int main() {
int a, b, c, x, y;
cin >> a >> b >> c;
int d = exgcd(a, b, x, y);
if (c % d == 0) {
printf("%d %d", c / d * x, c / d * y);
}
else {
puts("none");
}
return 0;
}