mod以及费马小定理的基本概念

一、定义

MOD,同余符号,在数学上,两个整数除以同一个整数,若得相同余数,则二整数同余(英文:Modular arithmetic;德文:Kongruenz)。同余理论常被用于数论中。最先引用同余的概念与符号者为德国数学家高斯。

二、扩展

如果x和y是任意实数,我们定义以下述二元运算:

x y = x - y * [x/y](向下取整) ,如果y0; 注释*( x 0) = x.(1)

从这个定义可以看出,当y0时,

0 x/y -[x/y](向下取整) = (x y) / y < 1. (2)

因此,

(a)如果y > 0, 那么 0 x y < y;

(b)如果y < 0, 那么0x mod y > y;

(c)x - (x mod y)是y的整数倍。

我们称x mod y 为y除x所得的余数,称[x/y](向下取整) 为商。

所以,当x和y为整数时,就是我们熟悉的取余数的运算:

5 3 = 2, 21 3 = 0, -2 3 = 1 (3)

当且仅当x是y的倍数时,也就是当且仅当x被y除尽时,有x y = 0. 记号y\x读作“y整除x”,表示y是一个正整数,且xy = 0.

所以,当x和y取任意实数值时,运算是有用的。例如,

x (x ).

x mod 1这个值是x的小数部分。由等式(1)有

x = [x](向下取整) + (x1). (4)

在数论中可以这样表示同余:陈述式

xy (modulo z) (5)

表示xz = yz,相当于“x-y是z的整数倍”.式(5)读作"x和y模z同余".

三、互素&同余

如果两个整数x和y没有大于1的公因数,即最大公因数为1,那么称它们是互素的,并记作xy.当一个分数的分子与分母互素时,我们习惯称之为“最简”分数。

定律A. 如果 ab(modulo m)且xy(modulo m), 那么axby且axby(modulo m).

定律B. 如果axby且ab(modulo m),而am,那么xy(modulo m).

定律C. 如果n0,那么ab(modulo m)当且仅当anbn(modulo m).

定律D. 如果rs,那么ab(modulo rs)当且仅当ab(modulo r)且ab(modulo s).

定律A说明,可以像普通的加减乘,对modulo m做同样的运用。

定律B则针对除法运算,表面当除数与模数m互素时,可以约去公因数。定律C和定律D考虑改变模数的结果。

四、费马小定理(1640).

如果p是一个素数,那么对于所有整数a,有a(modulo p)也就是1(modulo p)。

证明. 如果a是p的倍数,显然0a(modulo p).所以我们只需考虑a p 0的情况。如果p是素数,就意味着ap。考虑

0 p, a p, 2a p, ..., (p-1)ap (6)

这p个数两两不同,因为如果axp = ayp,那么由定义(5),ax ay(modulo p);因此,按定律B,xy(modulo p)。

由于式(6)给出p个不同的数,它们都是小于p的非负整数,第一个数为0,而其余的数是按某种次序排列的1,2,...,p-1。所以,按定律A,

(a)(2a)...((p-1)a)12...(p-1) (modulo p). (7)

同余式的两端同时乘a,得到

(12...(p-1)) a(12...(p-1)) (modulo p). (8)

因为每个因素1,2,...,p-1都与p互素,由定理B可以消去。

证毕

其实可以直接根据欧拉定理进行证明 欧拉定理,如下:

1(n)

当n为素数p时,它的欧拉函数为(p) = p-1,将它带入欧拉定理,得到:

1(p)

费马小定理,得证。

在此附上求欧拉函数的C++版本代码、

873. 欧拉函数

#include<bits/stdc++.h>
using namespace std;

int phi(int x) {
    int res = x;
    for(int i = 2; i <= x/i; ++i) {
        if(x % i == 0) {
            res = res/i*(i-1);
            while(x%i == 0) x /= i;
        }
    }
    if(x > 1) res = res/x*(x-1);
    return res;
}

int main() {
    int n;
    cin >> n;
    while(n--) {
        int m;
        cin >> m;
        cout << phi(m) << endl;
    }
    return 0;
}

874. 筛法求欧拉函数

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1000010;
int primes[maxn], euler[maxn], cnt;
bool st[maxn];

void get_eulers(int n) {
    euler[1] = 1;
    for(int i = 2; i <= n; ++i) {
        if(!st[i]) {
            primes[cnt++] = i;
            euler[i] = i-1;
        }
        for(int j = 0; primes[j] <= n/i; ++j) {
            int t = primes[j]*i;
            st[t] = 1;
            if(i % primes[j] == 0) {
                euler[t] = euler[i]*primes[j];
                break;
            }
            euler[t] = euler[i]*(primes[j]-1);
        }
    }
}
int main() {
    int n;
    cin >> n;
    get_eulers(n);
    ll res = 0;
    for(int i = 1; i <= n; ++i) res += euler[i];
    cout << res << endl;
    return 0;
}

五、素数判定和为素数

  1. 素数判定

对我们来说费马小定理有什么用?

一个直观的想法是:可以随机找几个和n互素的a,然后对它计算:

n

如果结果都为1,我们就可以认为n是一个素数。

如果这个结论成立,那么素数判定的时间复杂度就变成了O(C),其中C为常数,代表找C个a来做判定试验,O()则为利用二分快速幂进行判定的时间复杂度。

在此附上二分快速幂的C++版

875. 快速幂

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;


LL qmi(int a, int b, int p)
{
    LL res = 1 % p;
    while (b)
    {
        if (b & 1) res = res * a % p;
        a = a * (LL)a % p;
        b >>= 1;
    }
    return res;
}


int main()
{
    int n;
    scanf("%d", &n);
    while (n -- )
    {
        int a, b, p;
        scanf("%d%d%d", &a, &b, &p);
        printf("%lld\n", qmi(a, b, p));
    }

    return 0;
}

以上假设是成立的吗?

答案是:否!

  1. 伪素数

事实上,费马小定理给出的是关于素数判定的必要非充分条件。

如果p是素数,则1( p);相反,如果1( q),则不能推导出p是素数。

原因在一些数q,对于所有和q互素的a,都能满足1( q),这样的数,我们称之为伪素数。

第一个伪素数是341,由萨鲁斯在1819年提出。

费马小定理的应用

AcWing 876. 快速幂求逆元

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;


LL qmi(int a, int b, int p)
{
    LL res = 1;
    while (b)
    {
        if (b & 1) res = res * a % p;
        a = a * (LL)a % p;
        b >>= 1;
    }
    return res;
}


int main()
{
    int n;
    scanf("%d", &n);
    while (n -- )
    {
        int a, p;
        scanf("%d%d", &a, &p);
        if (a % p == 0) puts("impossible");
        else printf("%lld\n", qmi(a, p - 2, p));
    }

    return 0;
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值