乘法逆元和线性同余方程

这篇博客介绍了模意义下的乘法逆元概念,通过扩展欧几里得算法求解,并探讨了快速幂法在求解特定情况下的乘法逆元问题。还涉及到了线性同余方程的解法,强调了解的存在条件及求解步骤。此外,文章提供了C++代码示例来实现这些算法。
摘要由CSDN通过智能技术生成

乘法逆元通常说的是模意义下的乘法逆元,ax ≡ 1(mod b)则 x 称为 a mod b 的逆元 a^{-1}

洛谷:https://www.luogu.com.cn/problem/P3811

 我们首先考虑扩展欧几里得算法:

ax + by = gcd (a,b);

我们变换乘法逆元的公式:ax ≡ 1 (mod b)

(ax) % b = 1

ax - by = 1

这个形式看着是不是很熟悉

咱们再来回顾一下扩展欧几里得算法:

int exgcd(int a,int b,int &x,int &y)
{
    if(!b)
    {
        x = 1,y=0;
        return a;
    }
    else
    {
        int d = exgcd(b,a%b,y,x);
        y -= a/b *x;
        return d;
    }
}

但是由于上面的题很坑,被卡常

所以我们一顿操作下来:

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

//快读
template <typename L> inline void Read(L &x){
    char c;
    while((c=getchar())<'0'||c>'9');
    x=c^48;
    while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48);
}
//快写
template <typename L> void Write(L x){
    if(x>9) Write(x/10);
    putchar(x%10^48);
}
//扩欧
inline void exgcd(register int a,register int b,register int &x,register int &y){
    if(!b){x=1;y=0;}
    else{
        exgcd(b,a%b,x,y);
        register int k=x;
        x=y;y=k-(a/b)*y;
    }
}

int main(){
    register int n,p,x,y;
    Read(n);Read(p);
    for(register int i=1;i<=n;++i){
        exgcd(i,p,x,y);
        Write(x<0?x+p:x);
        putchar('\n');
    }
    return 0;
}

我们来看一个新的算法:

快速幂法:

当 p 为质数的时候,ax ≡ 1 (mod p)

根据费马小定理 a^{p-1} \equiv 1 (mod p)

ax \equiv a^{p-1} (mod p)

x \equiv a^{p-2}(mod p)

上代码:

int qpow(int a,int b)
{
	int res =1;
	while(b)
	{
		if(b&1) res =(LL)res * a % p;
		b>>=1;
		a = a*a % p; 
	}
	return res;
}

接下来,我们来看一下线性同余方程

形如:ax ≡ c (mod b)

没错就是乘法逆元但是系数变成了整数

ax - by = c

而扩欧是可以求出一组 x,y 使得 ax + by = gcd(a,b)

因此,我们获得整数解的条件就是 gcd(a,b) | c;

我们在公式两边同时除以gcd(a,b) 乘 c

c * \frac{ax}{gcd(a,b)} + c * \frac{by}{gcd(a,b)} =c

这样我们就可以获得一组解了

上代码:

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

typedef long long LL;

int exgcd(int a,int b,int &x,int &y)
{
    if(!b)
    {
        x = 1,y=0;
        return a;
    }
    else
    {
        int d = exgcd(b,a%b,y,x);
        y -= a/b *x;
        return d;
    }
}
int n;
int main()
{
    int a,b,c;
    scanf("%d%d%d",&a,&c,&b);
    int x,y;
    int d = exgcd(a,b,x,y);//gcd(a,b)
        
    if(c % d)puts("-1");
    else printf("%d\n",(LL)x*(c/d)%b);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

是饿梦啊

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

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

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

打赏作者

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

抵扣说明:

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

余额充值