模运算 及 逆元

1、四则运算均可进行取模运算(mod)。

在加法(与乘法相同)的取模运算中,可以写作

(a+b)modp=( amodp+bmodp )modp

但是减法的取模运算,1mod5 在计算机中的运算为 1 ,但正确的结果应为 4 ,所以减法取模为

(ab)modp=( ( amodpbmodp )+p )modp

异或的取模运算

(a xor b)modp=((amodp) xor b)modp

然而除法的取模却大不相同,因为对于

(12÷3)modp  12modp ÷3modp

此处引入 逆元 的概念,来解决对于除法的取模问题。


2、在取模意义下的除法——逆元。

概念:单位元 与 逆元

在一个集合中,对于某种运算 *(注意:这里代表通用运算的表示符号,并不是特指乘法),如果对于任何的集合元素 a,和元素 e 运算,得到还是集合元素 a 本身,则称 e 为这个运算下的单位元。
逆元素(逆元,指一个可以取消另一给定元素运算的元素)在一个集合中,对于某种运算 *,如果任意两个元素的运算结果等于单位元,则称这两个元素互为逆元。
加法的单位元为 0,其加法逆元为相反数。
乘法的单位元为 1,其乘法逆元为倒数。

在模运算中,
对于同余方程 ax1(modp) , 我们称 xa 在模 p 意义下的逆元,其单位元为 1(modp)

前提:裴蜀定理(或贝祖定理)可知,当且仅当 gcd(a,p)=1 时,a 在模 p 的情况下有逆元。

解决取模意义下的除法:÷a(modp)× a1(modp),即 在模 p 的意义下,一个数 a 有逆元除以 a 。(a1 是指 a 的逆元)

如何求逆元?(如何解决取模意义下的除法?)

答:扩展欧几里得、费马小定理、欧拉定理 . . .


i、扩展欧几里得求逆元

扩展欧几里得是用于求解不定方程 ax+by=c 的一组解的算法,但对于同余方程 ax1(modp) 也可以写作不定方程的形式:

axny=1 (  ax+n(y)=1)

由此可以求得 x 的值,即逆元的值。

int exgcd(int a, int b, int &x, int &y)
{
	if (b == 0)
	{
		x = 1, y = 0;
		return a;
	}
	int r = exgcd(b, a%b, y, x);
	y -= a/b*x;
	return r;
}
int Inv(int a, int n)
{
	int r, x, y;
	r = exgcd(a, n, x, y);
	return r==1?(x+n)%n:-1;
}

ii、费马小定理求逆元

费马小定理为:当模数 p 为质数时,存在

ap11(modp)

由于 ap1 可以写作 a×ap2 ,那么存在 a×ap21modp,所以 ap2 就是 a 在模 p 意义下的逆元。

由此可得,  ap2a1(modp)

利用快速幂快速求解 ap2

long long ksm(long long a, long long k)
{
	long long ans = 1;
	while (k)
	{
		if (k&1)
			ans = (ans * a) %mod;
		a = (a * a) %mod;
		k >>= 1; 
	}
	return ans;
}

long long Inv(long long a)
{
	return ksm(a, p-2);
}

iii、欧拉定理求逆元

在欧拉定理中,对于任意模数 m,有

aϕ(m)1(modm)

其中 ϕ(m) 为欧拉函数:对正整数 m,欧拉函数是小于或等于 m 的正整数中与 m 互质的数的数目。
由此可得,对于任意模数, aϕ(m)1a1(modm)


iv、线性求逆元

设模数 p=k×i+r,  (k,rZ),则有 p0(modp)

所以 k×i+r0(modp)

我们将方程两边同乘以 inv(i)×inv(r) 得到 k×inv(r)+inv(i)0(modp)

 inv(i)k×inv(r)modp

因为有 p=k×i+r,所以 k=ip,r=pmodi

inv(i)(ip×inv(pmodi))(modp)

为防止出现负数,写为

inv(i)((pip)inv(pmodi))(modp)

int Inv(int p)
{
	inv[1] = 1;
	for (int i = 1; i <= n; ++ i)
	{
		inv[i] = ((p - i/p)*inv[p % i]) %p;
	}
}

3、逆元与组合数

因为求组合数 C(n,m)=n!m!(nm)! 的过程中,可能涉及取模的运算,所以组合数就和逆元扯上了联系。

v、阶乘逆元(线性)

在组合数中,
f(x)=1x!,由此我们将 f(i)×i 可以得到 f(i)×i=1(i1)!=f(i1),我们可以解决快速地将 i[n1,1] 的阶乘求出来、

那么对 f(i)(modp) 就是要求其的逆元(通常 p 为素数),可以用上述 (iiii) 的方法求出。

又因为 f(i1)(modp)=(f(i)×i)(modp),所以可以快速的求出 组合数问题。


理解参考:
i.不错的模运算规则
ii.朝夕的ACM笔记 数论-逆元
iii.逆元 —— 广义化的倒数

posted @   Ciaxin  阅读(1185)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示