扩展欧几里得算法的模板实现

我居然现在还记不住扩欧的板子,我太弱啦!

扩展欧几里得算法解决的是这样的问题:

给定一个不定方程组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),则称ax在模p意义下的逆元

这里的符号意思是同余,也就是说左面对p的模等于右面

显然 它可以表示成ax-1p的整数倍

即形如: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;
}

  

以上

posted @ 2017-09-15 23:20  a799091501  阅读(563)  评论(0编辑  收藏  举报