基础数学总结 关于模运算 1

1.模运算基本公式 和 几点注意

/*
    (a + b) mod n = ((a mod n) + (b mod n)) mod n
    (a - b) mod n = ((a mod n) - (b mod n) + n) mod n
    (a * b) mod n = ((a mod n) * (b mod n)) mod n
    对于除法没有类似公式,但是可以通过求逆元的方法,转换成乘法运算求模(见下面)
*/

*注意:a是负数时a%m的结果也是负数 此时改为a%m+m就能保证结果在0~m-1范围内

            注意防范中间结果溢出危险

            当(a*c) mod p == (b*c) mod p时 (a-b)*c可以被p整除

            利用上边这个公式 可以实现对大整数的取模 (因为1234 = ((1*10+2)*10+3)*10+4 )


2.求逆元  

方法1:O(log max(a, m))

/*
  扩展欧几里得求 a 关于 模m 逆元  
  这个办法通用 但是若gcd(a, m) != 1逆元就是不存在的
*/
int extgcd(int a, int b, int &x, int &y){
    int d = a;
    if(b != 0){
        d = extgcd(b, a%b, y, x);
        y -= (a / b) * x;
    }
    else{
        x = 1; y = 0;
    }
    return d;
}
int mod_inverse(int a, int m){
    int x, y;
    extgcd(a, m, x, y);
    return (m + x%m) % m;
}

方法2:O(1)

这个方法求逆元需要用到下面讲到的 快速幂取模 运算,直接调用就好啦

插入一个定理

/*
    费马小定理:
    有a和p,如果p是质数,那么: a^(p - 1) % p = 1;
*/


/*
  如果 模p 是个素数, 那求逆元就变得很简单啦
  有费马小定理可得:
  a 关于 p 的逆元 aa = a^(p - 2) % p
  这是由于a^(p-1) % p = 1,等同于a * (a^(p-2)) % p = 1,所以a^(p-2)%p为逆元
*/


3.带模除法(逆元) O(log max(a, m)) 或 O(1)

这里介绍扩展欧几里得算法实现的求逆元 如果 模p 是个素数 则完全可以使用 费马小定理求逆元

/*
  (a / b) mod p == (a * bb) mod p
  bb是b关于p的逆元  bb = mod_inverse(b, p);
*/

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

    int a, b, p;
    while(scanf("%d%d%d",&a, &b, &p) != EOF){
        printf("1:   %d\n", (a/b) % p);     //正常除法取模
        int tmp = mod_inverse(b, p);
        printf("2:   %d\n", (a*tmp) % p);   //逆元除法取模
    }

    return 0;
}

4. 快速幂取模运算(反复平方法)

/*
  当n为偶数时 x^n = ((x^2)^(n/2)), 递归转化为n/2的情况
  当n为奇数时 x^n = ((x^2)^(n/2))*x, 同样也递归转为n/2的情况
  不断递归下去
*/

long long mod_pow(long long x, long long n, long long mod){
    if(n == 0) return 1;
    long long res = mod_pow(x*x%mod, n/2, mod);
    if(n&1) res = res * x % mod;
    return res;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值