GCD及EXGCD 复习笔记
GCD
辗转相除法
证明
设实数 和 ,我们要证明
-
证明
可以发现, , , 。
而 ,易知 。
同理,设 , ,那么 ,所以 。
-
由 1 可得, 是 的公因数,和上面相似可以证出 是 的公因数。由 的定义可知 且 即 。
-
而 重复减去 其实就是 取模。
Code
很简单,直接贴了。
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
-
注意 只能处理正数,负数处理方法见线性同余方程。
-
顺带一提,(最小公倍数)
题
EXGCD
原理要用到 ,但用处和 关联其实不是很大。
裴蜀定理
方程
至少有一组整数解。
证明
不难看出问题可以简化成:
其中,、 互质。即证明两个互质的数可以线性组合出 。
由 的过程我们发现,辗转相除的实质就是更相减损,即用两数线性组合。我们只要按照 gcd 过程倒推回来就行了,这个过程其实差不多就是 exgcd 了。
exgcd
根据裴蜀定理,我们知道,对于一个二元一次方程:
当 为 的整数倍时,方程有整数解。
那么如何解这个方程呢?
原理
当 时 ,我们将等式两边同除以 :
设 和 为 和 ,根据 的原理我们知道:
这样不断递归下去,直到:
然后回溯回去求得 和 。
Code
void exgcd(int a,int b,int &x,int &y){
if(b==0){
x=1;y=0;
}
else{
exgcd(b,a%b,y,x);
y-=(a/b)*x;
}
}
线性同余方程*
母题
求解
原式可以如下变换:
这样我们就能用 求解了。
这里要注意, 求解的是
我们要给求出的解进行处理才行。
下面我们来上题
例题
luogu P1082 MOD
模板啦直接贴代码
#include<cstdio>
#include<algorithm>
using namespace std;
void exgcd(int a,int b,int &x,int &y){
if(b==0){
x=1;
y=0;
}
else{
exgcd(b,a%b,y,x);
y-=(a/b)*x;
}
}
int main()
{
int a,b;
int x,y;
scanf("%d %d",&a,&b);
//a,b互质
exgcd(a,b,x,y);
printf("%d",((x%b)+b)%b);
return 0;
}
[luogu P1516] 青蛙ha的约会
- 题目大意:
求满足 的最小的 。
- 推柿子:
然后几乎就转化成裸题辽。
- 细节
我们发现 可能是负数,但是 只能处理正数,所以要小小变换一下。因为我们只需要知道 ,就可以这样:
#include<cstdio>
#include<algorithm>
typedef int int_;
#define int long long
using namespace std;
int n,m,wa,wb,l;
int mod(int o,int p){
return ((o%p)+p)%p;
}
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
void exgcd(int a,int b,int &x,int &y){
if(b==0){
x=1;y=0;
}
else{
exgcd(b,a%b,y,x);
y-=(a/b)*x;
}
}
int_ main()
{
scanf("%lld %lld %lld %lld %lld",&wa,&wb,&n,&m,&l);
wa=mod(wa,l);wb=mod(wb,l);
int a=m-n,b=l,c=wa-wb;
if(a<0){
a=-a;
c=-c;
}
int g=gcd(a,b);
if(c%g != 0){
printf("Impossible");
return 0;
}
a/=g;b/=g;c/=g;
int x,y;
exgcd(a,b,x,y);
x*=c;
x=mod(x,b);
printf("%lld",x);
return 0;
}
[luogu P2421] 荒岛野人
- 题目大意
和上题稍有不同,这题是两两求 在 内无正整数解。
- 做法
很简单,只需从小到大枚举 ,然后检验每两个人都不会相遇就ok。
#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 1000000
int n,maxx,c[20],p[20],l[20];
int mod(int o,int M){
return ((o%M)+M)%M;
}
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
void exgcd(int a,int b,int &x,int &y){
if(b==0){
x=1,y=0;
}
else{
exgcd(b,a%b,y,x);
y-=(a/b)*x;
}
}
bool work(int i,int j,int m){
int a=p[i]-p[j],b=m,d=c[j]-c[i];
if(a<0){
a=-a,d=-d;
}
int g=gcd(a,b);
if(d%g != 0){
return false;
}
a/=g,b/=g,d/=g;
int x,y;
exgcd(a,b,x,y);
x*=d;
x=mod(x,b);
if(x <= min(l[i],l[j])) return true;
else return false;
}
bool check(int m){
for(int i=1;i<n;i++){
for(int j=i+1;j<=n;j++){
if(work(i,j,m)){
return false;
}
}
}
return true;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d %d %d",&c[i],&p[i],&l[i]);
maxx=max(maxx,c[i]);
c[i]--;
}
for(int i=1;i<=maxn;i++){
if(check(i)){
printf("%d",max(maxx,i));
return 0;
}
}
return 0;
}
-EOF-
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫