逆元java_求逆元的四种方法

如果ax≡1(mod p),且a与p互质(gcd(a,p)=1),则称a关于模p的乘法逆元为x。(不互质则乘法逆元不存在)

求逆元的四种方法:

费马小定理

欧拉定理求逆元 (相当于费马小定理的扩展)

扩展欧几里德

递推打表

1、费马小定理 (p为素数)

a10b673788eb8430af33eb659266fd19.png

费马小定理:  ( a^p - p ) 是 p 的倍数,所以可推出

5b71e80b05f598bfd9ac9618c87a94323e41e688 , 这也是更为常用的书写形式。

因为 a^(p-1) = a * a^(p-2) , 故费马小定理可写成逆元的形式,( a * a^(p-2) ) ≡ 1 (mod p)

因此 a^(p-2) 就是所求的逆元,用快速幂求出即可。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 LL pow_mod(LL a, LL b, LL p){//a的b次方求余p

2 LL ret = 1;3 while(b){4 if(b & 1) ret = (ret * a) %p;5 a = (a * a) %p;6 b >>= 1;7 }8 returnret;9 }10 LL Fermat(LL a, LL p){//费马求a关于b的逆元

11 return pow_mod(a, p-2, p);12 }

View Code

2、欧拉定理求逆元

36c41808ec64a3cb6e6b56130394e6f0.png

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 #include

2 #include

3 #include

4 #include

5 #include

6 #include

7 #include

8 #include

9 #include

10 using namespacestd;11 typedef long longLL;12 const int N = 100009;13

14 intcheck[N];15 intprime[N];16 intphi[N];17 intinv[N];18 intcnt;19

20 int fast_pow(int a,intb)21 {22 int ans=1;23 while(b)24 {25 if(b&1)26 ans=a*ans;27 a=a*a;28 b>>=1;29 }30 returnans;31 }32

33 void is_prime(intn)34 {35 inti,p,j;36 cnt=0;37 phi[1]=1;38 for(i=2;i<=n;i++)39 {40 if(!check[i])41 {42 prime[cnt++]=i;43 phi[i]=i-1;44 }45 for(j=0;jn)48 break;49 check[i*prime[j]]=1;50

51 if(i%prime[j]==0)52 {53 phi[i*prime[j]]=phi[i]*prime[j];54 break;55 }56 else

57 {58 phi[i*prime[j]]=phi[i]*(prime[j]-1);59 }60 }61 }62 }63 intmain()64 {65 inti,p,j,n;66 is_prime(100);67 scanf("%d",&p);68 for(i=0;i<=10;i++)69 if(i%p)70 inv[i]=(fast_pow(i,phi[p]-1)%p); i关于1模p的逆元

71 else

72 inv[i]=-1;73 for(i=0;i<=10;i++)74 {75 printf("%d",inv[i]);76 }77 return 0;78 }

View Code

3、扩展欧几里德

a*x=1 (mod p)  相当于 a*x-y*p=1 (y为整数,最小的x应当是y等于零的时候,所以最后的时候把y赋成0)

a*x-y*p=1 , 为了便于理解,将p写成b,

即, a*x+b*y=1。 理解为 a关于 1 模 b 的乘法逆元为 x 。

开始的 x,y,d 为任意值,但是不能等于零!!!

因为d是 gcd(a,b),所以最后给d赋值为gcd的值。若d为1,说明存在这样的x,否则不存在。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 #include

2 #include

3 #include

4 #include

5 #include

6 #include

7 #include

8 #include

9 #include

10 #include

11 #include

12 #include

13 using namespacestd;14 typedef long longLL;15 const int N = 100009;16

17 void exgcd(LL a,LL b,LL &d,LL &x,LL &y)18 {19 if(b==0)20 {21 x=1;22 y=0;23 d=a;24 return;25 }26 else

27 {28 exgcd(b,a%b,d,x,y);29 LL mid=x;30 x=y;31 y=mid-a/b*y;32 }33

34 return;35 }36 LL inv(LL a, LL b)37 {38 LL x,y,d;39 exgcd(a,b,d,x,y);40 return d == 1 ? (x+b)%b : -1;41

42 }43 intmain()44 {45 LL a,p;46 scanf("%lld%lld",&a,&p);47 printf("%lld\n",inv(a,p));48 return 0;49 }

View Code

4、递推打表

令 a*x + b = p.

b * inv[b] ≡ 1 (mod p) , 将 b 替换为 p - a*x

(p - a * x) * inv[b] ≡ 1(mod p) ,即 p * inv[b] - (a * x * inv[b] ) ≡ 1(mod p)

因为 p mod p 等于零, 所以上式变为 -(a * x * inv[b]) ≡ 1(mod p)

观察 a * x + b = p 得 , 在计算机中 a = p/x , b = p%x .

故 - (p/x * inv[p % x] * x) ≡ 1(mod p)

因此  -p/x *inv[p % x] ≡ inv[x] (mod p)

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 #include

2 #include

3 #include

4 #include

5 #include

6 #include

7 #include

8 #include

9 #include

10 using namespacestd;11 typedef long longLL;12 const int N = 100009;13

14 intinv[N];15 intmain()16 {17 inti,p,j,n;18 scanf("%d%d",&n,&p);19 inv[1]=1;20 for(i=2;i<=n;i++)21 inv[i] = LL(p-p/i)*inv[p%i]%p;22 for(i=2;i<=n;i++)23 printf("%d %d \n",i,inv[i]);24

25 return 0;26 }

View Code

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值