我居然现在还记不住扩欧的板子,我太弱啦!
扩展欧几里得算法解决的是这样的问题:
给定一个不定方程组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是n的整数倍
即形如:ax-ny=1
那么根据上面扩展欧几里得定理的内容,我们显然可以发现只有gcd(a,n)=1,也就是互质的时候才有解,否则无解
#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.打表递推
适合于求范围内所有逆元
以上
原文:http://www.cnblogs.com/tsunderehome/p/7529112.html