zoukankan      html  css  js  c++  java
  • 求逆元的四种方法

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

    求逆元的四种方法:

    1. 费马小定理
    2. 欧拉定理求逆元 (相当于费马小定理的扩展)
    3. 扩展欧几里德
    4. 递推打表

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

    费马小定理:  ( a^p - p ) 是 p 的倍数,所以可推出 a^{{p-1}}equiv 1{pmod  {p}} , 这也是更为常用的书写形式。

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

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

     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     return ret;
     9 }
    10 LL Fermat(LL a, LL p){//费马求a关于b的逆元 
    11         return pow_mod(a, p-2, p);
    12 }
    View Code

    2、欧拉定理求逆元

    摘自大佬博客: https://www.cnblogs.com/vongang/archive/2013/06/04/3117370.html

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<string.h>
     4 #include<math.h>
     5 #include<algorithm>
     6 #include<queue>
     7 #include<stack>
     8 #include<deque>
     9 #include<iostream>
    10 using namespace std;
    11 typedef long long  LL;
    12 const int N = 100009;
    13 
    14 int check[N];
    15 int prime[N];
    16 int phi[N];
    17 int inv[N];
    18 int cnt;
    19 
    20 int fast_pow(int a,int b)
    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     return ans;
    31 }
    32 
    33 void is_prime(int n)
    34 {
    35     int i,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;j<cnt;j++)
    46         {
    47             if(i*prime[j]>n)
    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 int main()
    64 {
    65     int i,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,否则不存在。

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<string.h>
     4 #include<math.h>
     5 #include<algorithm>
     6 #include<queue>
     7 #include<stack>
     8 #include<map>
     9 #include<set>
    10 #include<vector>
    11 #include<deque>
    12 #include<iostream>
    13 using namespace std;
    14 typedef long long  LL;
    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 int main()
    44 {
    45     LL a,p;
    46     scanf("%lld%lld",&a,&p);
    47     printf("%lld
    ",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)    

      

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<string.h>
     4 #include<math.h>
     5 #include<algorithm>
     6 #include<queue>
     7 #include<stack>
     8 #include<deque>
     9 #include<iostream>
    10 using namespace std;
    11 typedef long long  LL;
    12 const int N = 100009;
    13 
    14 int inv[N];
    15 int main()
    16 {
    17     int i,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 
    ",i,inv[i]);
    24 
    25     return 0;
    26 }
    View Code
  • 相关阅读:
    c++ cout、cin、endl
    c++ namespace
    找到小镇的法官
    整数反转
    c++stack类的用法
    栈应用:最小栈(第二题)
    栈的压入、弹出序列(第一题)
    c++中vector类的用法
    Android 面试常问七道题
    传感器实现仿微信摇一摇功能
  • 原文地址:https://www.cnblogs.com/daybreaking/p/9342060.html
Copyright © 2011-2022 走看看