您的位置:首页 > 游戏 > 游戏 > 【算法模板】数论:裴蜀定理

【算法模板】数论:裴蜀定理

2024/10/5 14:55:30 来源:https://blog.csdn.net/2303_80346267/article/details/140644084  浏览:    关键词:【算法模板】数论:裴蜀定理

概念

裴蜀定理(Bézout’s Identity)是数论中的一个重要定理,涉及整数的线性组合。定理陈述如下:

对于任何整数 a 和 b,如果 d 是 a 和 b 的最大公约数,那么存在整数 x 和 y 使得: ax+by=d

换句话说,最大公约数 d 可以表示为 a 和 bbb 的线性组合。

欧几里得算法证明

欧几里得算法是一种用于计算两个整数的最大公约数的算法。我们可以利用这个算法来证明裴蜀定理。

  1. 算法步骤:
    • 如果 b=0 ,那么 a 就是 a 和 b 的最大公约数。此时 a=d ,且 a⋅1+b⋅0=a。
    • 否则,令 r 是 a 除以 b 的余数,即 a=bq+r ,其中 q 是商。然后用欧几里得算法递归地计算 b 和 r 的最大公约数。
  2. 证明过程:
    • 首先,我们知道 d=gcd⁡(a,b) 也是 d=gcd⁡(b,r) ,因为 r=a−bq 。根据递归过程,我们可以不断减小问题的规模,最终在某一步骤中,我们会得到 r=0 ,此时 b 是最大公约数。
    • 在每一步,我们可以记录线性组合的形式。具体来说: r=a−bq 如果我们知道 b 和 r 的最大公约数可以写成: b⋅x1+r⋅y1=d 那么我们可以用 r=a−bq 替换 r: b⋅x1+(a−bq)⋅y1=d 展开并整理得到: a⋅y1+b⋅(x1−qy1)=d 因此,我们可以看到 d 依然是 a 和 b 的线性组合。
  3. 详细的证明递归部分:
    • 初始情况:如果 b=0 ,则最大公约数 d=a ,且 a⋅1+b⋅0=a ,此时 x=1 和 y=0 。
    • 递归情况:使用欧几里得算法得到 a=bq+r ,则 gcd⁡(a,b)=gcd⁡(b,r) ,我们可以继续应用算法到 b 和 r 。通过递归地应用线性组合,我们最终可以写出最大公约数的形式。

通过这个过程,我们证明了裴蜀定理,即对于任何两个整数 a 和 b,它们的最大公约数 d 总可以表示成它们的某个线性组合形式 ax+by=d 。

推广

对于任意整数 a1,a2,…,an ,如果 d 是这些整数的最大公约数,那么存在整数 x1,x2,…,xn 使得: a1x1+a2x2+⋯+anxn=d

换句话说,多个整数的最大公约数 d 可以表示为这些整数的线性组合。

模板

inline int gcd(int x, int y) { return y ? gcd(y, x % y) : !x; }
int n;
int main() {scanf("%d", &n);int ans = 0, tmp;for (int i = 1; i <= n; i++) {scanf("%d", &tmp);if (tmp < 0) tmp = -tmp;ans = gcd(ans, tmp);}printf("%d", ans);
}

模板题

P4549 【模板】裴蜀定理 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

给定一个包含 n 个元素的整数序列 A,记作 A1, A2, A3, …, An。

我们的目标是求另一个包含 n 个元素的待定整数序列 X,其中 S = ∑(Ai × Xi)(i 从 1 到 n)。要求 S > 0 且 S 尽可能的小。

#include <bits/stdc++.h>
using namespace std;int main(){int n;cin>>n;vector<int> v(n);for(int &i:v)cin>>i;int g=v.front();for(int i:v)g=gcd(g,i);cout<<g<<endl;return 0;
}

B-Crash Test_2024牛客暑期多校训练营3 (nowcoder.com)

我们考虑以下碰撞测试的简化版本。最初,汽车的前部朝向墙壁,距离墙壁 D 米。该碰撞测试提供了 n 种助推器,其中第 i 种助推器的推力性能为 h,并且每种类型的助推器都有充足的数量。假设汽车前部和墙壁之间的当前距离为 d,我们使用推力性能为 h 的助推器。当 d≥h 时,汽车将向前移动 h 米,然后停止。否则,汽车将向前移动 d 米,撞到墙上,然后反弹 h−d 米,然后停下来,仍然面向墙壁。

现在,您想知道,通过任意数量的操作(包括无操作),汽车前部和墙壁之间的最小距离是多少?

#include <bits/stdc++.h>
using namespace std;
#define int long longsigned main() {int n,m;cin>>n>>m;vector<int> v(n);for(int &i:v)cin>>i;int g=v.front();for(int i:v)g=gcd(g,i);int x=m/g;cout<<min(m-x*g,(x+1)*g-m);return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com