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

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

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

给定一个不定方程组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.打表递推

适合于求范围内所有逆元

以上

时间: 2024-10-11 17:16:02

扩展欧几里得算法的模板实现的相关文章

扩展欧几里得算法模板题 zoj 3609

Modular Inverse Time Limit: 2 Seconds      Memory Limit: 65536 KB The modular modular multiplicative inverse of an integer a modulo m is an integer x such that a-1≡x (mod m). This is equivalent to ax≡1 (mod m). Input There are multiple test cases. Th

欧几里得算法与扩展欧几里得算法_C++

先感谢参考文献:http://www.cnblogs.com/frog112111/archive/2012/08/19/2646012.html 注:以下讨论的数均为整数 一.欧几里得算法(重点是证明,对后续知识有用) 欧几里得算法,也叫辗转相除,简称 gcd,用于计算两个整数的最大公约数 定义 gcd(a,b) 为整数 a 与 b 的最大公约数 引理:gcd(a,b)=gcd(b,a%b) 证明: 设 r=a%b , c=gcd(a,b) 则 a=xc , b=yc , 其中x , y互质

【hdu1576】A/B——扩展欧几里得算法

扩展欧几里得的模板题,要记住: x=y1; y=x1-a/b*y1. 这道题的推导过程如下: 1.因为A/B==0,所以令A/B=x,即A=Bx.又因为n=A%m,所以m*y+n=A. 由上面可推导出Bx-my=n. 2.由扩展欧几里得算法可以算出B*x1+m*y1=1的根,等式两边同时乘上n可以变形为B*(x1*n)-m*(-n*y1)=n. 所以x=n*x1.到这里我们只需要通过扩欧算出x1,答案即为(x1*n)%m. 3.最后要注意的一点,扩展欧几里得算法算出的x1可能为负数,这显然是不成

POJ - 1061 青蛙的约会 (扩展欧几里得算法)

Description 两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置.不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的.但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的.为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面. 我们把这

[NOI2002] 荒岛野人 扩展欧几里得算法

[问题描述] 克里特岛以野人群居而著称.岛上有排列成环行的M个山洞.这些山洞顺时针编号为1,2,-,M.岛上住着N个野人,一开始依次住在山洞 C1,C2,-,CN中,以后每年,第i个野人会沿顺时针向前走Pi个洞住下来.每个野人i有一个寿命值Li,即生存的年数.下面四幅图描述了一个有6个 山洞,住有三个野人的岛上前四年的情况.三个野人初始的洞穴编号依次为1,2,3:每年要走过的洞穴数依次为3,7,2:寿命值依次为4,3,1.     奇怪的是,虽然野人有很多,但没有任何两个野人在有生之年处在同一个

扩展欧几里得算法(extgcd)

相信大家对欧几里得算法,即辗转相除法不陌生吧. 代码如下: int gcd(int a, int b){ return !b ? gcd(b, a % b) : a; } 而扩展欧几里得算法,顾名思义就是对欧几里得算法的扩展. 切入正题: 首先我们来看一个问题: 求整数x, y使得ax + by = 1, 如果gcd(a, b) != 1, 我们很容易发现原方程是无解的.则方程ax + by = 1有正整数对解(x, y)的必要条件是gcd(a, b) = 1,即a, b 互质. 此时正整数对解

欧几里得算法以及扩展欧几里得算法(过河noip2005提高组第二题)

欧几里得算法:也被称作辗转相除法 gcd(a,b)=gcd(b,a%b); 终止条件a=gcd b=0; (gcd为a,b的最大公约数) 扩展欧几里得算法: a 和 b 的最大公约数是 gcd ,一定能够找到这样的 x 和 y ,使得: a*x + b*y = gcd 成立 我们只需要找到特殊解x0,y0; 则通解为 x = x0 + (b/gcd)*t    y = y0 – (a/gcd)*t 那如何求出下一组解呢 仿照欧几里得算法a=b,b=a%b代入. a%b = a - (a/b)*b

扩展欧几里得算法学习记

话说以前我刷noip题的时候就想学这个东西了,结果却一直拖到了现在…… 到了高二才会这种东西的我实在是个蒟蒻啊! 将扩展欧几里得算法之前,先讲讲欧几里得算法是什么:gcd(a,b)=gcd(b,a%b).很显然是不?但我们还是要给出证明(设r=a%b): 设x是a,b的一个公约数,由于存在k使得a=k*b+r,又由于a|x,b|x,则有r|x,所以x是b,r的公约数 设x是b,r的一个公约数,因为存在k使得a=k*b+r,且b|x,r|x,那么a|x,所以x是a,b的公约数 综上所述,a和b的所

HDU - 1576 A/B(扩展欧几里得算法)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1576 题意:要求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1). 普通版欧几里得算法(辗转相除): 1 typedef long long LL; 2 LL gcd(LL a,LL b){ 3 return (b==0) ? a : gcd(b,a%b); 4 } 扩展欧几里得算法(理论):对于不完全为0的非负整数,