裴蜀定理(又称贝祖定理)
理论
一定存在整数 x,yx, yx,y,满足 ax+by=gcd(a,b)ax + by = gcd(a, b)ax+by=gcd(a,b)
例 4x+6y=24x + 6y = 24x+6y=2,有整数解 x=−1,y=1x = -1, y = 1x=−1,y=1。
而 4x+6y=34x + 6y = 34x+6y=3,即 x=3−6y4x = \frac{3 - 6y}{4}x=43−6y 无整数解。
证明:
设取整数 x0,y0x_0, y_0x0,y0 时,ax+byax + byax+by 的最小正整数为 sss
即 ax0+by0=sax_0 + by_0 = sax0+by0=s
因 gcd(a,b)∣ax0gcd(a, b) \mid ax_0gcd(a,b)∣ax0,gcd(a,b)∣by0gcd(a, b) \mid by_0gcd(a,b)∣by0,
故 gcd(a,b)∣s⋯⋯(1)gcd(a, b) \mid s \cdots\cdots (1)gcd(a,b)∣s⋯⋯(1)
设 a=qs+r(0≤r<s)a = qs + r (0 \leq r < s)a=qs+r(0≤r<s)
r=a−qsr = a - qsr=a−qs
=a−q(ax0+by0)= a - q(ax_0 + by_0)=a−q(ax0+by0)
=a(1−qx0)+b(−qy0)= a(1 - qx_0) + b(-qy_0)=a(1−qx0)+b(−qy0)
=ax+by= ax + by=ax+by
因 sss 是最小正整数,故 r=0r = 0r=0
所以 s∣as \mid as∣a,同理 s∣bs \mid bs∣b,
故 s∣gcd(a,b)⋯⋯(2)s \mid gcd(a, b) \cdots\cdots (2)s∣gcd(a,b)⋯⋯(2)由 (1)(2)(1)(2)(1)(2) 得 s=gcd(a,b)s = gcd(a, b)s=gcd(a,b)。证毕。
裴蜀定理推广
一定存在整数 x,yx, yx,y,满足 ax+by=gcd(a,b)×nax + by = gcd(a, b) \times nax+by=gcd(a,b)×n
例 4x+6y=84x + 6y = 84x+6y=8,有整数解 x=−4,y=4x = -4, y = 4x=−4,y=4。
裴蜀定理再推广
一定存在整数 X1⋯XiX_1 \cdots X_iX1⋯Xi,满足 ∑i=1nAiXi=gcd(A1,A2,⋯ ,An)\sum_{i = 1}^{n} A_iX_i = gcd(A_1, A_2, \cdots, A_n)∑i=1nAiXi=gcd(A1,A2,⋯,An)
例 4x1+6x2+2x3=44x_1 + 6x_2 + 2x_3 = 44x1+6x2+2x3=4,有整数解 x1=1,x2=0,x3=0x_1 = 1, x_2 = 0, x_3 = 0x1=1,x2=0,x3=0。
裴蜀定理扩展
ax+by=nax + by = nax+by=n
结论:
- 若 n>ab−a−bn > ab - a - bn>ab−a−b,有解
- 若 n=0n = 0n=0,有解
- 若 n<0n < 0n<0,无解
- 若 ax+by=nax + by = nax+by=n 有解,则 ax+by=ab−a−b−nax + by = ab - a - b - nax+by=ab−a−b−n 无解
注意
欧几里得算法求 gcd(a,b)gcd(a, b)gcd(a,b)
如果代入负数,结果会返回负数
例:gcd(8,−4)=−4gcd(8, -4) = -4gcd(8,−4)=−4
如果系数 AiA_iAi 为负数,
求 gcdgcdgcd 时可代入其绝对值,
确保所求最大公约数为正数,
这样并不会影响解的存在。
例题
P4549 【模板】裴蜀定理
题目描述
给定一个包含 nnn 个元素的整数序列 AAA,记作 A1,A2,A3,...,AnA_1,A_2,A_3,...,A_nA1,A2,A3,...,An。
求另一个包含 nnn 个元素的待定整数序列 XXX,记 S=∑i=1nAi×XiS=\sum\limits_{i=1}^nA_i\times X_iS=i=1∑nAi×Xi,使得 S>0S>0S>0 且 SSS 尽可能的小。
输入格式
第一行一个整数 nnn,表示序列元素个数。
第二行 nnn 个整数,表示序列 AAA。
输出格式
一行一个整数,表示 S>0S>0S>0 的前提下 SSS 的最小值。
输入输出样例 #1
输入 #1
2
4059 -1782
输出 #1
99
说明/提示
对于 100%100\%100% 的数据,1≤n≤201 \le n \le 201≤n≤20,∣Ai∣≤105|A_i| \le 10^5∣Ai∣≤105,且 AAA 序列不全为 000。
#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:
求 ax+by=gcd(a,b)ax + by = gcd(a, b)ax+by=gcd(a,b) 的一组整数解
当 b=0b = 0b=0 时 ax+by=aax + by = aax+by=a 故而 x=1,y=0x = 1, y = 0x=1,y=0
当 b≠0b \neq 0b=0 时
由欧几里得算法,gcd(a,b)=gcd(b,a%b)gcd(a, b) = gcd(b, a\%b)gcd(a,b)=gcd(b,a%b)
由裴蜀定理,
gcd(a,b)=ax+bygcd(a, b) = ax + bygcd(a,b)=ax+by
gcd(b,a%b)=bx1+(a%b)y1gcd(b, a\%b) = bx_1 + (a\%b)y_1gcd(b,a%b)=bx1+(a%b)y1
=bx1+(a−⌊ab⌋×b)y1= bx_1 + (a - \lfloor\frac{a}{b}\rfloor\times b)y_1=bx1+(a−⌊ba⌋×b)y1
=ay1+b(x1−aby1)= ay_1 + b(x_1 - \frac{a}{b}y_1)=ay1+b(x1−bay1)
所以 x=y1x = y_1x=y1,y=x1−aby1y = x_1 - \frac{a}{b}y_1y=x1−bay1
可以用递归算法,先求出下一层的 x1,y1x_1, y_1x1,y1,再回代到上一层,层层回代,可求特解(x0,y0)(x_0, y_0)(x0,y0)
构造通解
{x=x0+bgcd(a,b)∗ky=y0−agcd(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 (考虑 ax+by=0ax + by = 0ax+by=0 构造)
例:8x+6y=28x + 6y = 28x+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:
求不定方程 ax+by=cax + by = cax+by=c 的一组整数解
- 若 gcd(a,b)∣cgcd(a, b) \mid cgcd(a,b)∣c,则有整数解
- 先用扩欧算法求 ax+by=gcd(a,b)ax + by = gcd(a, b)ax+by=gcd(a,b) 的解
- 再乘以 c/gcd(a,b)c / gcd(a, b)c/gcd(a,b),即得原方程的特解(x0,y0)(x_0, y_0)(x0,y0)
- 例:8x+6y=68x + 6y = 68x+6y=6,解得 x=3,y=−3x = 3, y = -3x=3,y=−3
构造通解
{x=x0+bgcd(a,b)∗ky=y0−agcd(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 (考虑 ax+by=0ax + by = 0ax+by=0 构造)
- 若 gcd(a,b)∤cgcd(a, b) \nmid cgcd(a,b)∤c,则无整数解。
- 例:8x+6y=38x + 6y = 38x+6y=3,x=3−6y8x = \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;
}