• 数论——逆元


    总:逆元

    一、数论倒数,又称逆元

    注意是数论倒数,不是数学的倒数。

    你以为a的倒数在数论中还是1/a吗?哼哼~天真
    看一下上次说的

    二、余数性质

    (a + b) % p = (a%p + b%p) %p (对)
    (a - b) % p = (a%p - b%p) %p (对)
    (a * b) % p = (a%p * b%p) %p (对)
    (a / b) % p = (a%p / b%p) %p (错)

    对于一些题目,我们必须在中间过程中进行求余,否则数字太大,电脑存不下,那如果这个算式中出现除法,我们是不是对这个算式就无法计算了呢?

    答案当然是 NO (>o<)
    这时就需要逆元了
    我们知道
    如果
    ax = 1
    那么x是a的倒数,x = 1/a
    但是a如果不是1,那么x就是小数
    那数论中,大部分情况都有求余,所以现在问题变了
    a
    x = 1 (mod p) (这是个啥?:传送门)
    那么x一定等于1/a吗
    不一定
    所以这时候,我们就把x看成a的倒数,只不过加了一个求余条件,所以x叫做 a关于p的逆元
    比如2 * 3 % 5 = 1,那么3就是2关于5的逆元,或者说2和3关于5互为逆元
    这里3的效果是不是跟1/2的效果一样,所以才叫数论倒数
    a的逆元,我们用inv(a)来表示

    那么(a / b) % p = (a * inv(b) ) % p = (a % p * inv(b) % p) % p

    这样就把除法,完全转换为乘法了 ,用性质即可
    那么,,,

    三、如何求逆元?

    (忘了说,a和p互质,a才有关于p的逆元)

    3.1求逆元方法一:费马小定理

    因为
    a^(p-1) ≡1 (mod p)
    两边同除以a
    a^(p-2) ≡1/a (mod p)
    什么(,,• ₃ •,,),这可是数论,还敢写1/a
    应该写a^(p-2) ≡ inv(a) (mod p)
    所以

    inv(a) = a^(p-2) (mod p)

    这个用快速幂求一下,复杂度O(logn)(ง •̀_•́)ง

    long long pow_mod(long long a, long long b, long long p){//a的b次方求余p 
        long long ret = 1;
        while(b){
            if(b & 1) ret = (ret * a) % p;
            a = (a * a) % p;
            b >>= 1;
        }
       return ret;
    }
    long long Fermat(long long a, long long p){
            return pow_mod(a, p-2, p)%p;
    }
    

    3.2求逆元方法二:扩展欧几里德算法

    还记得扩展欧几里德吗?(不记得的话,欧几里得会伤心的(╭ ̄3 ̄)╭♡)
    ax + by = 1
    如果ab互质,有解
    这个解的x就是a关于b的逆元
    y就是b关于a的逆元
    为什么呢?
    你看,两边同时求余b
    ax % b + by % b = 1 % b
    ax % b = 1 % b
    a
    x = 1 (mod b)
    你看你看,出现了!!!(/≥▽≤/)
    所以x是a关于b的逆元
    反之可证明y

    代码:

    #include<cstdio>
    typedef long long LL;
    void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d){
        if (!b) {d = a, x = 1, y = 0;}
        else{
            ex_gcd(b, a % b, y, x, d);
            y -= x * (a / b);
        }
    }
    LL inv(LL t, LL p){//如果不存在,返回-1 
        LL d, x, y;
        ex_gcd(t, p, x, y, d);
        return d == 1 ? (x % p + p) % p : -1;
    }
    int main(){
        LL a, p;
        while(~scanf("%lld%lld", &a, &p)){
            printf("%lld
    ", inv(a, p));
        }
    }
    

    3.3求元方法三:线性预处理逆元

    求一个区间上的逆元:

    当p是个质数的时候有

    inv(a) = (p - p / a) * inv(p % a) % p

    代码:

    // p 必须为质数,p / i 为整除。
    inv[1] = 1;
    for (int i = 2; i <= n; ++i) {
        inv[i] = (p - p / i) * inv[p % i] % p;
    }
    

    本文转载

    转载于文章:https://blog.csdn.net/Liukairui/article/details/7984702

  • 相关阅读:
    使用FolderBrowserDialog组件选择文件夹
    使用OpenFileDialog组件打开多个文
    使用OpenFileDialog组件打开对话框
    获取弹出对话框的相关返回值
    PAT 甲级 1139 First Contact (30 分)
    PAT 甲级 1139 First Contact (30 分)
    PAT 甲级 1138 Postorder Traversal (25 分)
    PAT 甲级 1138 Postorder Traversal (25 分)
    PAT 甲级 1137 Final Grading (25 分)
    PAT 甲级 1137 Final Grading (25 分)
  • 原文地址:https://www.cnblogs.com/fisherss/p/10012427.html
Copyright © 2020-2023  润新知