拓展欧几里得算法——C.一日之计在于晨
1.拓展欧几里得算法——C.一日之计在于晨
2.菜狗的KMP学习谈到拓展欧几里得算法,就要从欧几里得算法和裴蜀定理说起。
欧几里得算法(辗转相除法)
其中,当
时, ; 同理
证明:
令
主要是证明
同理,
推广一下,相当于
int gcd(int a,int b){
if(b==0)return a;
return gcd(b,a%b);
}
参考:
辗转相除法的原理 _辗转相除法求最大公约数的原理是什么? (shadafang.com)
裴蜀定理(贝祖定理)
设
是不全为0的整数,对任意整数 ,满足 ,且存在整数 ,使得
首先证明任意整数
令
再证明存在整数
设取整数
且
设
同理,
拓展欧几里得算法
拓展欧几里得算法实际上就是求
当
此时,
当
由欧几里得算法可知,
由裴蜀定理可知,
利用递归,先求出下一层的
构造通解
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;
}
求 的一组整数解
由拓展欧几里得算法可知,我们可以求
那么,如果
若
例题
题目
题解
根据指针的转动,可以列出 (只是大致的,未考虑加一/减一)
移动,
我们就可以根据拓展欧几里得算法求得
这样就可以求得特解
最后再根据通解,求出
代码
#include <bits/stdc++.h>
#define int long long
#define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
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;
}
void solve(){
int t,a,m;
cin>>t>>a>>m;
int x,y;
int d=exgcd(a,m,x,y);
t=(t-1)%d+1-t; //这里就省略了re
x=((x*t/d)%m+m)%m; //特解
x=(x%(m/d)+(m/d))%(m/d); //通解
cout<<min(x,m/d-x)<<endl;
}
signed main()
{
ios;
int T;
cin>>T;
while(T--){
solve();
}
return 0;
}