zoukankan      html  css  js  c++  java
  • 扩展欧几里得、费马小定理 求逆元都在这里

    欧拉定理(又称费马-欧拉定理):已知a和n为正整数,并且a和p互素,则a^phi(n) ≡ 1(mod n)。

    证明:

      设集合Z = {X1, X2, X3, .... , Xphi(n)},其中Xi (i = 1, 2, .. phi(n))表示第i个不大于n与n互质的数。

      考虑集合S = {a*X1(mod n), a*X2(mod n), ... ,a*Xphi(n) (mod n) },则集合Z = S;

      1) 因为a和n互质,Xi和n也互质,所以a*Xi 也与n互质。所以对任意一个Xi,a*Xi (mod n)一定是Z里面的元素;

      2)对于任意Xi, Xj, 如果Xi != Xj,则a*Xi(mod n) != a*Xj(mod n);

      所以S = Z;

      那么 (a*X1*a*X2*...*a*Xphi(n))(mod n) ---------------------------------------------------- (1)

      = (a*X1(mod n)* a*X2(mod n)* ... *a*Xphi(n) (mod n)) (mod n)

      = (X1* X2* X3* .... * Xphi(n)) (mod n) ------------------------------------------------------ (2)

      式(1)整理得 [a^phi(x) * (X1* X2* X3* .... * Xphi(n))] (mod n)

      与(2)式一同消去 (X1* X2* X3* .... * Xphi(n)),即得 a^phi(n) ≡ 1 (mod n);

    逆元 :(b/a) (mod n) = (b * x) (mod n)。 x表示a的逆元。并且 a*x ≡ 1 (mod n )  注意:只有当a与n互质的时候才存在逆元

    因为a^phi(n) ≡ 1 (mod n),所以x可以表示为a^(phi(n) - 1)。如果n为质数,phi(n)=n-1

    /*扩展欧几里得的应用:
    模P乘法逆元
    对于整数a、p,如果存在整数b,满足ab mod p =1,则说,b是a的模p乘法逆元。
    定理:a存在模p的乘法逆元的充要条件是gcd(a,p) = 1

    注意,逆元也可以这样理解,求一个最小的正整数x(逆元),使a乘以x对m的取余等于1对m的取余, 所以m=1 时,逆元为1

    证明:
    首先证明充分性
    如果gcd(a,p) = 1,根据欧拉定理,aφ(p) ≡ 1 mod p,因此
    显然aφ(p)-1 mod p是a的模p乘法逆元。

    再证明必要性
    假设存在a模p的乘法逆元为b
    ab ≡ 1 mod p
    则ab = kp +1 ,所以1 = ab - kp
    因为gcd(a,p) = d
    所以d | 1
    所以d只能为1 
    扩展欧几里德算法对于最大公约数的计算和普通欧几里德算法是一致的。计算乘法逆元则显得很难明白。下面是证明:

    首先重复拙作整除中的一个论断:

    如果gcd(a,b)=d,则存在m,n,使得d = ma + nb,称呼这种关系为a、b组合整数d,m,n称为组合系数。当d=1时,有 ma + nb = 1 ,此时可以看出m是a模b的乘法逆元,n是b模a的乘法逆元。
    (按照上面算出来的m,n可能为负数,最后要把它转化为正数)。完整程序如下:*/

    一般情况下,ax+by=1;得 x为a mod  b 的逆元,y为 b mod a的逆元

    #include <iostream>
    using namespace std;
    int extended_gcd(int a,int b, int &x, int &y)
    {
    if (b == 0)
    {
    x = 1;
    y = 0;
    return a;
    }
    else
    {
    int gcd = extended_gcd(b, a % b, x, y);
    int t=x%mod;
       x=y%mod;
       y=((t-a/b*x)%mod+mod)%mod;
    return gcd;
    }
    }
    int main()
    {
    int i, x, y;
    const int P = 13;
    for (i = 1; i < P; ++i)
    {
    extended_gcd(i, P, x, y);
    while (x < 0) x += P;
    printf("1 div %d = %d
    ", i, x);
    }
    return 0;
    }

    费马小定理求逆元

    //费马小道理求逆元
    #include<iostream>
    #include<cstdio>
    #include<math.h>
    #include<string.h>
    using namespace std;
    
    #define N 1005
    int b[N],prime[N],phi[N];
    void inint()  //求欧拉函数 和 素数
    {
        int i,j,k,c=0;
        memset(b,0,sizeof(b));
        for(i=2;i<N;i++)
        {
            if(b[i]==0)
            {
                prime[++c]=i;
                phi[i]=i-1;
            }
            for(j=1;(j<=c)&&(k=i*prime[j])<N;j++)
            {
                b[k]=1;
                if(i%prime[j])
                {
                   phi[prime[j]*i]=phi[i]*(prime[j]-1);
    
                }
                else phi[prime[j]*i]=phi[i]*prime[j];
            }
        }
    }
    
    int m;
    int poww(int a,int n)
    {
       int r=1,p=a;
       while(n>0)
       {
           if(n&1) r=(r*p)%m;
           p=(p*p)%m;
           n>>=1;
       }
       return r;
    }
    
    int main()
    {
        int t,a,i,j,f;
        inint();
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&a,&m);
            f=0;
            if(m==1)  //注意 m为1时,逆元都为1
            {
                 puts("1");
                continue;
            }
            for(i=1;;i++)
            {
                if(prime[i]>a||prime[i]>m) break;
                if(a%prime[i]==0&&m%prime[i]==0)
                {
                    f=1;
                    break;
                }
            }
            if(f)  //a和m 不互素,不存在逆元
    
            {
                puts("Not Exist");
                continue;
            }
            int x=poww(a,phi[m]-1);  //求解 a 模 m 的逆元
            x=(x%m+m)%m;
            printf("%d
    ",x);
        }
        return 0;
    }

    //扩展的欧几里德算法求乘法逆元

    #include <stdio.h>
    int ExtendedEuclid(int f, int d, int *result);
    int main() {
    int x, y, z;
    z = 0;
    printf("输入两个数:
    ");
    scanf("%d%d", &x, &y);
    if (ExtendedEuclid(x, y, &z))
    printf("%d和%d互素,乘法的逆元是:%d
    ", x, y, z);
    else
    printf("%d和%d不互素,最大公约数为:%d
    ", x, y, z);
    return 0;
    }
    
    int ExtendedEuclid(int f, int d, int *result)//求f 模  d 的 逆元
     {
    int x1, x2, x3, y1, y2, y3, t1, t2, t3, q;
    x1 = y2 = 1;
    x2 = y1 = 0;
    x3 = d;
    y3 = f;
    while (1) {
    if (y3 == 0) {
    *result = x3; /* 两个数不互素则result为两个数的最大公约数,此时返回值为零 */
    return 0;
    }
    if (y3 == 1) {
    *result = y2; /* 两个数互素则resutl为其乘法逆元,此时返回值为1 */
    return 1;
    }
    q = x3 / y3;
    t1 = x1 - q*y1;
    t2 = x2 - q*y2;
    t3 = x3 - q*y3;
    x1 = y1;
    x2 = y2;
    x3 = y3;
    y1 = t1;
    y2 = t2;
    y3 = t3;
    }
    
    }
  • 相关阅读:
    webpack 项目接入Vite的通用方案介绍(上)
    AQS的原理及源码分析
    宝宝喂养
    Java日期时间操作基础——包含JDK1.8时间操作新特性
    ThreadLocal的正确使用与原理
    网络编程基础
    如何优雅正确地通过interrupt方法中断线程
    JavaWeb入门到实战学习笔记
    File与IO基础
    枚举基础
  • 原文地址:https://www.cnblogs.com/xxas2015/p/6121000.html
Copyright © 2011-2022 走看看