数论 - 逆元及费马小定理

逆元

在费马小定理之前,我们先引入逆元的概念,考虑求解一个同余线性方程

axb(modm)
,要怎样求解这个方程呢,在此之前,我们先看一下求解一般的线性方程的方法,一般地,我们能将一个一元一次方程化为如下的形式: ax=b ,那么在a有倒数的情况下,我们可以轻松地解出这个方程,那么同余线性方程呢?假设我们有一个方程 ay1(modm) ,并记这个方程的解为 a1 ,即a的逆元,那么 x=a1ax=ab ,即可求得方程的解.
现在的问题就变为了求解方程 ay1(modm) ,
假设我们已经求得该方程的解,那么肯定存在整数k,使其满足以下等式:
ay=mk+1

我们将式子稍稍变形:
aymk=1

就变成了求这个式子的解!是不是看起来很眼熟?其实就是之前讲到的扩展欧几里得算法.
用扩展欧几里得算法求解这个式子后,我们就能求a的逆元啦

代码如下

int extgcd(int a,int b,int &x,int &y){
    int ans=a;
    if(b==0){
        x=1;
        y=0;
    }
    else{
        ans=extgcd(b,a%b,y,x);
        y-=a/b*x;
    }
    return ans;
}
int mod_inverse(int a,int m){
    int x;
    int y;
    extgcd(a,m,x,y);
    return (m+x%m)%m;
}

模版题

http://acm.hdu.edu.cn/showproblem.php?pid=1576(HDU-1576)

题意

已知a%9973下的数n和b,a是b的倍数,且b与9973互质,求(a/b)%9973

题解

直接求带除法的取模运算是困难的,因为除法时取余与乘法,加法不同,可能改变结果,例如:

12/3%5=4
12%5/3=0.66666

因此我们考虑逆元,因为a是b的倍数,令 a=bx ,则 bxn(mod9973) ,而要求的答案就是 (a/b)%9973=(bx/b)%9973=x%9973 ,故只要求出b的逆元再乘上n即可求解
附AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int MOD=9973;
int n;
int gcd(int a,int b){
    if(b==0) return a;
    return gcd(b,a%b);
}
int extgcd(int a,int b,int &x,int &y){
    int ans=a;
    if(b==0) {
        x=1;
        y=0;
    }
    else{
        ans=extgcd(b,a%b,y,x);
        y-=(a/b)*x;
    }
    return ans;
}
int mod(int b,int m){
    int x,y;
    extgcd(b,m,x,y);
    return (m+(x*n)%m)%m;
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        LL b;
        scanf("%d %lld",&n,&b);
        printf("%d\n",mod(b,9973));
    }   
}

费马小定理

在上述背景下,我们引入费马小定理;
它的内容如下:
假设有一质数p与整数a,使得a,p互质(即gcd(a,p)=1),那么它们满足如下关系:

ap11(modp)

证明? 不会,留个坑先.
这个式子对于我们有什么好处,或者说有什么应用呢,我们对它稍稍变形:
ap2a1(modp)

其中 a1 就是a的逆元,利用这个定理,我们可以利用快速幂快速求解特定情况下的逆元.

代码如下

int power_mod(int x,int n,int p){
    int res=1;
    while(n){
        if(n&1) res=(res*x)%p;
        x=(x*x)%p;
        n>>=1;
    }
    return res;
}
int get_mod(int a,int p){
    return power_mod(a,p-2,p);
}

费马小定理推广(欧拉定理)

费马小定理讨论的是p为质数的情况,对于p不是质数,我们可以将其推广至欧拉定理,其内容如下:
假设有两个整数a,n互质,那么它们有如下关系

aφ(n)1(modn)

其中 φ(n) 为欧拉函数,关于其的定义如下:
φ(n)=n(pi1)/pi
因为n的整数分解可以在 O(n) 时间内求得,因此求某一个数的欧拉函数的时间复杂度也是 O(n)

求欧拉函数值代码

int eular_phi(int n){
    int res=n;
    for(int i=2;i*i<=n;i++){
        if(n%i==0){
            res=res/i*(i-1);
            while(n%i==0){
                n/=i;
            }
        }
        if(n!=1) res=res/n*(n-1);
        return res; 
    }
}

筛出欧拉函数值的表代码

利用埃拉托色尼筛法,我们可以O(n)实现筛表,之后O(1)查询,代码如下:

int eular[MAXN];
void eular_phi(){
    for(int i=0;i<MAXN;i++){
        eular[i]=i;
    }
    for(int i=2;i<MAXN;i++){
        if(eular[i]=i){
            for(int j=i;j<MAXN;j+=i){
                eular[i]=eular[j]/i*(i-1);
            }
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值