• 数论篇5——数论四大定理


    数论四大定理:

    • 威尔逊定理
    • 欧拉定理
    • 孙子定理(中国剩余定理)
    • 费马小定理

    1.威尔逊定理

    在初等数论中,威尔逊定理给出了判定一个自然数是否为素数的充分必要条件。

    当且仅当$p$为素数时

    $(p-1)!equiv -1(mod p)$

    简单点说就是,若$p$为质数,则$p$能被 $(p-1)!+1$ 整除

    但是由于阶乘是呈爆炸增长的,其结论对于实际使用不太多。

    证明

    首先,可以明确

    $(p-1)equiv -1(mod p)$

    根据同余式的性质,我们只需要证明

    $(p-2)!equiv 1(mod p)$

    这个式子突然就有点熟悉了,看下逆元的定义

    $acdot a^{-1}equiv 1(mod p)$

    我们考虑其实就是对于 $1,2,3,...,p−2 $去找模$p$意义下的逆元,而1的逆元就是1,不需要考虑

    然后根据

    $x^{2}equiv 1(mod p)$

    可以解得

    $x_{1}=1,x_{2}=p-1$ 

    意思就是只有1,$p-1$在模$p$意义下的逆元是自己,然而这两个数已经被我们安排了,然后逆元还有唯一性互反性。

    那么这些数自然是一一对应,所以$(p-2)!equiv 1(mod p)$成立。

    2.欧拉定理

     如果$n,a$为正整数,且$n,a$互质,则$a^{varphi(n)}=1(mod n)$

    欧拉函数的定义与实现

    证明

    将1~n中与n互质的数按顺序排布:

    $x_{1},x_{2},x_{3}...x_{varphi(n)}$ 

    我们考虑这么一些数:

    $m_{1}=a*x_{1};m_{2}=a*x_{2};m_{3}=a*x_{3}...m_{varphi(n)}=a*x_{varphi(n)}$

    需要两个引理,证明就不详细展开了。

    1)这些数中的任意两个都不模n同余

    2)这些数除n的余数都与n互质

    由1)和2)可知

    数$m_{1},m_{2},m_{3}...m_{varphi(n)}$(如果将其次序重新排列)必须相应地同余于$x_{1},x_{2},x_{3}...x_{varphi(n)}$ 

    故得出:

    $m_{1}*m_{2}*m_{3}...m_{varphi(n)}equiv x_{1}*x_{2}*x_{3}...x_{varphi(n)}(mod n)$

    $a^{varphi(n)}(x_{1}*x_{2}*x_{3}...x_{varphi(n)})equiv x_{1}*x_{2}*x_{3}...x_{varphi(n)}(mod n)$

    $K(a^{varphi(n)}-1)equiv 0(mod n) $这里$K=x_{1}*x_{2}*x_{3}...x_{varphi(n)}$

    可知

    $K(a^{varphi(n)}-1)$

    被n整除,但$K$中的因子都与$n$互质,所以$K$与$n$互质。那么

    $a^{varphi(n)}-1$

    必须能被$n$整除,即

    $a^{varphi(n)}-1equiv 0(mod n) $

    $a^{varphi(n)}equiv 1(mod n) $

    得证。

    3.费马小定理

    能看出来,欧拉定理是费马小定理的推广,所以欧拉定理也叫费马-欧拉定理,就不详细展开了。

    顺便一提一下,费马大定理:

    当整数$n >2$时,关于$x, y, z$的方程$ x^{n} + y^{n} = z^{n}$没有正整数解。

    4.中国剩余定理(孙子定理)

    问题描述

      “今有物不知其数,三三数之余二,五五数之余三,七七数之余二。问物几何?”

    转换成数学语言,就是求解一次同余式组

    egin{cases}
    xequiv a_1(mod m_1)  \
    xequiv a_2(mod m_2)  \
    xequiv a_3(mod m_3)  \
    ... \
    xequiv a_n(mod m_n)  \
    end{cases}

    其中$a_i, m_i$均为正数,模数$m_i$两两互素。

    定理

    令$M=prod_{i=1}^{n}m_{i}$,即$M$是$m_i$的最小公倍数

    $e_i$为$frac{M}{m_i}cdot e_iequiv 1(mod m_i)$的最小非负整数解

    则有对于原方程组有唯一解

    $x=sum_{i=1}^{k}a_ie_i frac{M}{m_i} (mod M)$

    代码实现:

    void exgcd(int a, int b, int& x, int& y)
    {
        if (b == 0) { x = 1; y = 0; return; }
        exgcd(b, a % b, x, y);
        int temp = x;
        x = y; y = temp - a / b * y;
    }
    
    int crt(int* a, int* m, int k)
    {
        int res, x, y, M = 1;
        for (int i = 1; i <= k; ++i) M *= m[i];
        for (int i = 1; i <= k; ++i)
        {
            exgcd(M / m[i], m[i], x, y);
            if (x < 0)
                x += m[i];
            res = (res + M / m[i] * x * a[i]) % M;
        }
        return res % M;
    }

    模板题

    https://www.luogu.org/problemnew/solution/P3868

    #include <iostream>
    #include <fstream>
    using namespace std;
    
    typedef long long LL;
    
    LL m[10], a[10], k;
    //数据可能会爆long long
    LL quick_mult(LL a, LL b, LL M) {
        LL res = 0;
        while (b) {
            if (b & 1)
                res = (res + a) % M;
            a = (a + a) % M;
            b >>= 1;
        }
        return res % M;
    }
    void ex_gcd(LL a, LL b, LL&x, LL&y) {
        if (b == 0) {
            x = 1; y = 0;
            return;
        }
        ex_gcd(b, a % b, x, y);
        LL temp = x;
        x = y;
        y = temp - a / b * y;
    }
    
    LL crt() {
        LL M = 1;
        LL e[10];
        LL except_mi[10];
        for (int i = 0; i < k; i++) {
            M *= m[i];
        }
        for (int i = 0; i < k; i++) {
            LL x,y;
            ex_gcd(M / m[i], m[i], x, y);
            if (x < 0)
                x += m[i];
            e[i] = x;
    
        }
    
        LL res = 0;
        for (int i = 0; i < k; i++) {
            (a[i] % m[i] + m[i]) % m[i];//a[i]可能为负数,根据同余性质,取正
            res = res % M + quick_mult(e[i], quick_mult(M / m[i], a[i], M), M);
        }
        return res % M;
    }
    
    int main() {
    #ifdef LOCAL
        fstream cin("data.in");
    #endif // LOCAL
        cin >> k;
        for (int i = 0; i < k; i++) {
            cin >> a[i];
        }
        for (int i = 0; i < k; i++) {
            cin >> m[i];
        }
        cout << crt();
        return 0;
    }
    View Code
  • 相关阅读:
    Elasticsearch通关
    Zookeeper是什么
    手把手带你了解消息中间件(1)——基础
    为什么要分库分表
    mysql的innodb 引擎 表锁与行锁
    MySQL中Innodb的聚簇索引和非聚簇索引
    Redis主从和集群
    redis防止抢购商品超卖
    Laravel 核心--Facades 门面
    PHP数据库操作:使用ORM
  • 原文地址:https://www.cnblogs.com/czc1999/p/11693795.html
Copyright © 2020-2023  润新知