扩展欧几里得算法

44 篇文章 0 订阅
16 篇文章 0 订阅

扩展欧几里得算法

  • The extended Euclidean algorithm is an algorithm to compute integers x x x and y y y such that a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b) , given a a a and b b b .

  • 扩欧是对辗转相除法做了一些扩展,缩写 e x g c d ( ) exgcd() exgcd()

  • 考虑辗转相除法递推到边界, b = 0 , a = g c d b=0,a=gcd b=0,a=gcd

    • 得到边界的解 x = 1 , y = 0 x=1,y=0 x=1,y=0
  • 反递推上一层的解:

    • 当前层: b x 1 + ( a % b ) y 1 = g c d bx_1+(a\%b)y_1=gcd bx1+(a%b)y1=gcd
      g c d = b x 1 + ( a − [ a b ] ∗ b ) y 1 = a y 1 + b ( x 1 − [ a b ] y 1 ) \begin{aligned} gcd&=bx_1+(a-[\frac{a}{b}]*b)y_1\\ &=ay_1+b(x_1-[\frac{a}{b}]y_1) \end{aligned} gcd=bx1+(a[ba]b)y1=ay1+b(x1[ba]y1)

    • 反推到上一层: x = y 1 , y = x 1 − [ a b ] y 1 ) x=y_1,y=x_1-[\frac{a}{b}]y_1) x=y1,y=x1[ba]y1)

  • 注意:方程 a x + b y = g c d ax+by=gcd ax+by=gcd 的解不唯一

    • x 0 , y 0 x_0 ,y_0 x0,y0 是解,则 x 0 + t ∗ b / g c d   和   y 0 − t ∗ a / g c d x_0+t*b/gcd\ 和\ y_0-t*a/gcd x0+tb/gcd  y0ta/gcd 也是解, t ∈ N t\in N tN要理解

P1082 [NOIP2012 提高组] 同余方程

#include <bits/stdc++.h>
#define int long long 
using namespace std;

void exgcd(int a,int b,int &x,int &y)
{
    if(!b) { x=1; y=0; return; } // 边界
    exgcd(b,a%b,x,y); // 当前层
    int t=y; 
    y=x-a/b*y; x=t; // 解出上一层的
}

signed main()
{
    ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int a,b;
    cin>>a>>b;
    int x=0,y=0;
    exgcd(a,b,x,y);
    x=(x%b+b-1)%b+1; // 最小正整数解
    cout<<x<<endl;
    return 0;
}
  • 该题的另一种写法:
    • 条 件 是 : a x ≡ 1 ( m o d   b ) , 欧 拉 函 数 : a φ ( b ) ≡ 1 ( m o d   b ) 条件是:ax\equiv 1(mod\ b),欧拉函数:a^{\varphi(b)}\equiv1(mod\ b) ax1(mod b)aφ(b)1(mod b)
    • 再根据同余的传递性: a x ≡ a φ ( b ) ( m o d   b ) ax\equiv a^{\varphi(b)}(mod\ b) axaφ(b)(mod b)
    • 解得: a n s = k s m ( a , e u l e r ( b ) − 1 , b ) ans=ksm(a,euler(b)-1,b) ans=ksm(a,euler(b)1,b)
  • 能用欧拉函数来解的前提: a , b a,b a,b 互质(题目保证有解, a , b a,b a,b 必然互质)
#include <bits/stdc++.h>
#define int long long 
using namespace std;

int euler(int x)//欧拉函数
{
	int ans=x,sq=sqrt(x*1.0);
	for(int i=2;i<=sq;i++)
	{
		if(x%i==0)
		{
			ans=ans-ans/i;
			while(x%i==0) x/=i;
		}
	}
	if(x>1) ans=ans-ans/x;
	return ans;
}
int ksm(int a,int b,int p)
{
    int ans=1;
    while(b)
    {
        if(b&1) ans=ans*a%p;
        a=a*a%p; b >>= 1;
    }
    return ans;
}

signed main()
{
    ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int a,b;
    cin>>a>>b;
    int ans=ksm(a,euler(b)-1,b);
    cout<<ans<<endl;
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yezzz.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值