扩展欧几里得算法的模板实现
我居然现在还记不住扩欧的板子,我太弱啦!
扩展欧几里得算法解决的是这样的问题:
给定一个不定方程组ax+by=gcd(a,b),求他的一组整数解
先给出实现代码
void exgcd(int a,int b,int &x,int &y) { if(!b) { x=1,y=0;//gcd(a,0)显然等于1*a-0*0=a return a; } int ans=exgcd(b,a%b,x,y); int tem=x; x=y; y-=tem-(a/b)*y; return ans;
}
但实际正常题目是没有需要你求出一组不定方程的所有解的..而这个算法的经典应用就是求解乘法逆元
逆元:如果a*x≡1(mod p),则称a是x在模p意义下的逆元
这里的符号意思是同余,也就是说左面对p的模等于右面
显然 它可以表示成ax-1是p的整数倍
即形如:ax-py=1
那么根据上面扩展欧几里得定理的内容,我们显然可以发现只有gcd(a,p)=1,也就是互质的时候才有解,否则无解
....相信很多人看到这里其实是没懂...至少蒟蒻博主就没懂
口胡一下人话定义
如果a是x在模p意义下的逆元,那么也就相当于a是模p意义下x的倒数
上代码
#pragma GCC optimize("O2") #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> #include<stack> #include<set> #include<map> #include<limits.h> #include<ctime> #define N 100001 typedef long long ll; const int inf=0x3fffffff; const int maxn=2017; using namespace std; inline int read() { int f=1,x=0;char ch=getchar(); while(ch>'9'|ch<'0') { if(ch=='-') f=-1; ch=getchar(); } while(ch<='9'&&ch>='0') { x=(x<<3)+(x<<1)+ch-'0'; ch=getchar(); } return f*x; } int exgcd(int a,int b,int &d,int &x,int &y) { if(!b) { x=1,y=0;//gcd(a,0)显然等于1*a-0*0=a return a; } exgcd(b,a%b,d,y,x); y-=a/b*x; } int cal(int a,int p) { int d,x,y; exgcd(a,p,d,x,y); return d==1?(x+p)%p:-1;//如果有解直接返回范围在0到p之间的解 } int main() { int a=read(),b=read(); printf("%d",cal(a,b)); }
是不是简单又整洁呢?期望时间复杂度O(ln n),编程复杂度也是很低的说x
其他求法
1.费马小定理
时间复杂度带一个log,比扩欧慢一些
2.特殊情况
转自http://blog.csdn.net/guhaiteng/article/details/52123385 其他部分也写的很棒 强烈安利
3.打表递推
适合于求范围内所有逆元
void init() { inv[0]=inv[1]=1; for(int i=2;i<mod;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod; }
以上
就让我永远不在这里写下什么有意义的话——by 吉林神犇 alone_wolf