引入裴蜀定理:
有任意一对正整数a、b,一定存在非零整数x、y,使得a*x+b*y=gcd(a,b),且gcd(a,b)是a、b添加系数后凑出来的最小正整数。
证明一下:
假设a*x+b*y=d
则需要证明的是:d是gcd(a,b)的倍数
因为a是gcd(a,b)的倍数,b是gcd(a,b)的倍数,
则 a*x+b*y也是gcd(a,b)的倍数
所以我们求的gcd(a,b)是a、b添加系数后凑出来的最小正整数。
那我们想证明一定存在的话,就是我们要接下来要说的拓展欧几里得算法了。
拓展欧几里得算法是为了算出这样的一组x,y。
题面:

采用递归的思路来求解:
当b==0时,任何数与0的最大公约数都是它本身。
当b==0时,a*x+0*y=a要成立的话,一组解为x=1,y=0;
其他的情况就是一直递归:
int d=exgcd(b,a%b,y,x),这里可以注意到这里传入的数值顺序改变了,读者自行理解一下
我们就有了这个式子:gcd(a,b)=gcd(b*y+a%b*x)
而a%b=a-a/b*b (a/b注意向下取整)
展开右边有:d=b*y+a*x-a/b*x
=a*x+b(y-a/b*x)
即
y=y-a/b*x;
x=x;
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10;
const int mod=1e9+7;
int exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y=y-a/b*x;
return d;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
ll n;
cin>>n;
while(n--)
{
int a,b,x,y;
cin>>a>>b;
exgcd(a,b,x,y);
cout<<x<<" " <<y<<endl;
}
return 0;
}
拓展欧几里得算法例题:
题面:

思路:
题目要求的是满足 ai × xi ≡ bi (mod mi)的xi。
举个例子a=4,b=3,m=5时,4 * x % 5 = 3 % 5, x = 2 或 -3 (2,-3互余于5)
由此我们只需要找出a * x % m = b
[所以存在一个正整数y ,使得上式等价变形为] a * x = y * m + b
a * x - y * m = b
有上面的拓展欧几里得算法解释,我们可以知道,b一定是gcd(a,b)的倍数,否者不存在x
如果是倍数的话,x可以表示为x*( b / gcd(a,b) ) % m。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10;
const int mod=1e9+7;
//拓展欧几里得算法模板
int exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x=1,y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y=y-a/b*x;
return d;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
ll n;
cin>>n;
while(n--)
{
int a,b,m;
cin>>a>>b>>m;
int x,y;
int d=exgcd(a,m,x,y);//求出来了a,b的最大公约数
if(b%d!=0)//即b不是gcd(a,b)的倍数
cout<<"impossible"<<endl;
else cout<<(ll)x*(b/d)%m<<endl;
}
return 0;
}

9872

被折叠的 条评论
为什么被折叠?



