关于乘法逆元的世界

  • 引子

  经过几天的努力,终于将逆元这个大难题给攻克了……心情激动的一时无法平复。下面就简单介绍一下关于逆元的知识,来记录自己的成果,也希望能够帮助到别人。某些地方可能理解的不够深入,还请多多包涵。

  • 定义

  逆元,又称数论倒数,如果a*x≡1 (mod p),且gcd(a,p)=1(a与p互质),则称a关于模p的乘法逆元为x。(来自维基百科)

  怎么说呢,逆元其实就是一个相当于倒数的东西,只不过是多模了一个p而已。要说它有什么用,那么请回忆一下倒数有什么用吧。没错,在上小学时,老师就教导过我们,除以一个数,就是乘它的倒数。其实,逆元也是充当这个“倒数”这个角色。还记得吗,在模运算中:

(a+b) % p == ( a%p + b%p )% p;

(a-b) % p  == (a%p - b%p + p) % p;(否则可能为负数)

(a×b) % P == (a%p) * (b%p) %p;

But

(a/b) % p != (a%p) / (b%p) % p  。!

所以呢,我们可以用到一个叫做逆元的东西:

(a / b) = ( a * inv(b))

so, (a / b) % p = (a%p) * (inv(b)%p) % p

这个式子可以配合lucas定理解决一系列问题。

其实逆元的用处还有很多,配合lucas定理只是其中一个。

由于他的意义和用处实在是太深奥了,作为一名蒟蒻,还不具备将它的全部用处解释出来的能力,对于用处就先写到这吧。

  • 求解?

逆元的求法有很多种,介于本人实力有限,着重将以下三种解法:

1、费马小定理(Fermat‘s little theorem)

(又称费小马定理)

定理如下:假如是质数,且gcd(a,p)=1,那么有 a(p-1)≡1(mod p)(来自Wikipedia)

为什么说可以用它求呢?

a(p-1) ≡ 1(mod p) ---->   a * a(p-2)≡1(mod p)

是不是和逆元的定义很像?

so,如果p是素数,那么a(p-2)就是a的逆元。

神奇吧!

关于a(p-2),我们可以用快速幂来求。

核心代码如下:

 1 long long fp(long long n,long long k,long long p)
 2 {
 3     long long s = k,ans = 1,t = n;
 4     while(s){
 5         if(s & 1)
 6             ans *= t%p;
 7         t *= t%p;
 8         s >>= 1;
 9     }
10     return ans % p;
11 }
12 long long inv(long long N,long long P)
13 {
14     return fp (N,P-2,P) % P;
15 }

第2种方法就是用拓展欧几里徳算法。

其描述如下:

对于a * x + b * y == gcd(a,b),若a,b互质,那么

ax + by == 1

将两边同时mod b得:

a * x ≡ 1 (mod b)

所以x是a关于b的逆元,亦可证明y是b关于a的逆元。

所以只要求出它的解来就行了

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cmath>
 4 using namespace std;
 5 typedef long long ll;
 6 ll n,p;
 7 void Euc(ll a,ll b,ll& x,ll& y)
 8 {
 9     if(!b){ x = 1; y = 0; }
10     else{ Euc(b,a%b,y,x); y -= (a/b)*x; }
11 }
12 ll inv(ll N,ll P)
13 {
14     ll X,Y;
15     Euc(N,P,X,Y);
16     X = (X%P + P) % P;
17     return X;
18 }
19 int main()
20 {
21     scanf("%lld%lld",&n,&p);
22     for( int i = 1; i <= n; i++)
23         printf("%lld\n",inv(i,p));
24     return 0;
25 }

至于拓欧的求法……

3、用递推来求:

有这麽一个等式:

inv(a) == (p - p / a) * inv(p % a) % p

证明:

待续。。。

所以。用递推很好解决:

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 typedef long long LL;
 5 const int MAXN = 3000001;
 6 LL n,p;
 7 LL inv[MAXN];
 8 void Inv()
 9 {
10     inv[1] = 1;
11     for( int i = 2; i <= n; i++)
12         inv[i] = (p - p/i) * (inv[p%i]%p) % p;
13 }
14 int main()
15 {
16     scanf("%lld%lld",&n,&p);
17     Inv();
18     for( int i = 1; i <= n; i++)
19         printf("%lld\n",inv[i]);
20     return 0;
21 }

最后,不得不感叹一句:探索知识的道路真是千辛万苦啊……

——————————————————————————————— continue ————————————————————————————————————

原文地址:https://www.cnblogs.com/hnfms-jerry/p/8597310.html

时间: 2024-11-10 11:18:18

关于乘法逆元的世界的相关文章

HDU3037 Saving Beans(Lucas定理+乘法逆元)

题目大概问小于等于m个的物品放到n个地方有几种方法. 即解这个n元一次方程的非负整数解的个数$x_1+x_2+x_3+\dots+x_n=y$,其中0<=y<=m. 这个方程的非负整数解个数是个经典问题,可以+1转化正整数解的个数用插板法解决:$C_{y+n-1}^{n-1}=C_{y+n-1}^y$. 而0<=y<=m,最后的结果就是—— $$\sum_{i=0}^m C_{i+n-1}^i$$ $$C_{n-1}^0+C_{n}^1+C_{n+1}^2+\dots+C_{n-1

UVa 11174 (乘法逆元) Stand in a Line

题意: 有n个人排队,要求每个人不能排在自己父亲的前面(如果有的话),求所有的排队方案数模1e9+7的值. 分析: <训练指南>上分析得挺清楚的,把公式贴一下吧: 设f(i)为以i为根节点的子树的排列方法,s(i)表示以i为根的子树的节点总数. f(i) = f(c1)f(c2)...f(ck)×(s(i)-1)!/(s(c1)!s(c2)!...s(ck)!) 按照书上最开始举的例子,其实这个式子也不难理解,就是先给这些子树确定一下位置,即有重元素的全排列. 子树的位置确定好以后,然后再确定

LightOJ - 1050 (唯一分解+推公式+乘法逆元)

题意:求a^b的所有约数和对1e9+7取模的结果 思路:对于一个数p,进行唯一分解,则p=P1^M1*P2^M2*...*Pn^Mn,则p的所有约数之和等于(P1^0+P1^1+...+P1^M1)*(P2^0+P2^1+...+P2^M2)*...*(Pn^0+Pn^1+...+Pn^Mn), p^t=P1^(M1*t)*P2^(M2*t)*...*Pn^(Mn*t),每一个(Pn^0+Pn^1+...+Pn^Mn)利用等比数列可以直接推出公式为(Pn^(Mn*t+1)-1)/(Pn-1),用

【奇技淫巧】数学技巧之乘法逆元

一.写在前面 开始码这篇blog之前我就意识到,这篇blog将会是我到目前为止码出的所有blog中最水的一篇.说是讲乘法逆元,但蒟蒻博主自己都不会证明_(:з」∠)_所以只打算放一个说明书式的用法,还请诸位看官老爷轻喷. 二.关于乘法逆元 我们知道模法交配率(Magic Coitus Law)(←_←其实并没有这东西)并不适用于除法.用式子表示大概是这样的: 但乘法逆元(Multiplicative Inverse Modulo,下式中用a'表示)就可以完成这样一个奇妙的操作: 然后我们就能用模

乘法逆元...Orz

最近打的几场比赛,都出现了有关逆元的题目,今天就整理了一下... 求乘法逆元的几种方法:http://www.cnblogs.com/james47/p/3871782.html 博文转载链接:http://blog.csdn.net/acdreamers/article/details/8220787 今天我们来探讨逆元在ACM-ICPC竞赛中的应用,逆元是一个很重要的概念,必须学会使用它. 对于正整数和,如果有,那么把这个同余方程中的最小正整数解叫做模的逆元. 逆元一般用扩展欧几里得算法来求

Codeforces 543D Road Improvement(树形DP+乘法逆元)

题目大概说给一棵树,树的边一开始都是损坏的,要修复一些边,修复完后要满足各个点到根的路径上最多只有一条坏的边,现在以各个点为根分别求出修复边的方案数,其结果模1000000007. 不难联想到这题和HDU2196是一种类型的树形DP,因为它们都要分别求各个点的答案.然后解法也不难想: dp0[u]表示只考虑以u结点为根的子树的方案数 dp1[u]表示u结点往上走,倒过来,以它父亲为根那部分的方案数 有了这两部分的结果,对于各个点u的答案就是dp0[u]*(dp1[u]+1).这两部分求法如下,画

乘法逆元(转)

定义:满足a*k≡1 (mod p)的k值就是a关于p的乘法逆元. 为什么要有乘法逆元呢? 当我们要求(a/b) mod p的值,且a很大,无法直接求得a/b的值时,我们就要用到乘法逆元. 我们可以通过求b关于p的乘法逆元k,将a乘上k再模p,即(a*k) mod p.其结果与(a/b) mod p等价. 证: 根据b*k≡1 (mod p)有b*k=p*x+1. k=(p*x+1)/b. 把k代入(a*k) mod p,得:(a*(p*x+1)/b) mod p               

乘法逆元及其应用

满足 a * k ≡ 1 (mod p) 的k 叫做 a关于p的乘法逆元.另一种表达方法是 k ≡ a-1 (mod p) 逆元在密码学中有广泛应用,AES密码体系的字节替代就是运用了逆元.(不知道说的smg) 应用: 我们知道(a+b)%p=(a%p+b%p)%p (a*b)%p=(a%p)*(b%p)%p 而求(a/b)%p时,可能会因为a是一个很大的数,不能直接算出来,却又不能(a/b)%p=(a%p/b%p)%p. 但是可以通过 k ≡ b-1 (mod p)  a / b = a *

loj #110. 乘法逆元

#110. 乘法逆元 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 这是一道模板题. 给定正整数 n nn 与 p pp,求 1∼n 1 \sim n1∼n 中的所有数在模 p pp 意义下的乘法逆元. 输入格式 一行两个正整数 n nn 与 p pp 输出格式 n nn 行,第 i ii 行一个正整数,表示 i ii 在模 p pp 意义下的乘法逆元. 样例 样例输入 10 13 样例输出