扩展欧几里得算法:
ax+by=gcd(a,b) 求出满足条件唯一的x,y的值
设:
a为r0,b为r1
r0=q1∗r1+r2
r1=q2∗r2+r3
r2=q3∗r3+r4
..........
rk−1=qk∗rk
其中 rk 就是最大公约数,现在我们可以得到 0∗rk−1+rk=gcd.
又因为 rk可以写成 rk−1和 rk−2的代表公式即 rk=rk−2−qk−1∗rk−1,所以我们又能得到 x∗rk−2+rk−1=gcd的 x 和 y 了
同理 rk−3和rk−2也可向上表示。一直向上回溯即可找到满足条件 x∗a+y∗b=gcd的 x , y
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
ll ExGcd(ll a,ll b,ll &x,ll &y)//求 a b 最大公约数,且得到gcd(a,b)=x*a+y*b;
{
if(!b)
{
x=1;
y=0;
return a;
}
ll gcd=ExGcd(b,a%b,x,y);
ll temp,k;
k=a/b;
temp=x;
x=y;
y=temp-k*y;
return gcd;
}
利用扩展欧几里得求一次同余方程
gcd(a,m) | c ,即gcd(a,m) 是c的因子
形如式子 a∗x=c (mod m),求满足条件的x。
- 且只有满足 gcd(a,m)∣c 的时候才有解。
设 ax1+my1=gcd(a,m) ①
令 c1=c/gcd(a,m),
那么等式①两边同乘以 c1即可得到 ax1c1+my1∗c1=c
即 x=x1∗c1=x1∗c/gcd(a,m)( x1为 (a,m)的扩展欧几里得公式中a的系数)
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
ll ExGcd(ll a,ll b,ll &x,ll &y)//求 a b 最大公约数,且得到gcd(a,b)=x*a+y*b;
{
if(!b)
{
x=1;
y=0;
return a;
}
ll gcd=ExGcd(b,a%b,x,y);
ll temp,k=a/b;
temp=x;
x=y;
y=temp-k*y;
return gcd;
}
bool IsOk;
ll calc(ll a,ll c,ll m)
{
ll x,y;
ll gcd=ExGcd(a,m,x,y);
if(c%gcd!=0)
{
IsOk=false;
return 0ll;
}
return c/gcd*x%m;
}
利用费马小定理求逆元
补充一个 欧拉定理:
设φ(x)的x的欧拉函数值,如果有a和p互素,则有
aφ(p)=1(mod p)
- 费马小定理条件:a,p互素,且p是素数
则: ap−1=1 (mod q)
即: a 关于 p 的逆元为 ap−2
/* 快速幂取模即可 */
利用扩展欧几里得求逆元
前提
gcd(a,q)==1
逆元即ax+qy=1 (mod q)中的x
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
const int maxn=1e4+10;
ll ExGcd(ll a,ll b,ll &x,ll &y)//求 a b 最大公约数,且得到gcd(a,b)=x*a+y*b;
{
if(!b)
{
x=1;
y=0;
return a;
}
ll gcd=ExGcd(b,a%b,x,y);
ll temp,k;
k=a/b;
temp=x;
x=y;
y=temp-k*y;
return gcd;
}
ll getinv(ll a,ll m)
{
ll x,y;
if(ExGcd(a,m,x,y)!=1)
return -1;//不互质 不存在逆元
return x;
}