• 乘法逆元


    由于模意义下的除法运算不具有封闭性,所以我们得找一种办法将除法转换成其他的运算,下面就介绍了在模意义下取代除法运算的一种方法--乘法逆元

    定义:若整数b,m互质,并且b|a,则存在一个整数x使得$ frac{a}{b} equiv a*x (mod m) $ ,称x为b的模m的乘法逆元,记为$b^{-1}(mod m) $,也可以记为inv(b)。(倒数

    因为 $$ a/b equiv a*b^{-1} equiv a/b *b *b^{-1} (mod m ) $$

    所以 $ b^{-1}*b equiv 1 (mod m) $

    若m为质数且b<m,根据费马小定理$ b^{m-1} equiv 1 (mod m) $,所以 $b*b^{m-2} equiv 1 (mod m) $
    所以当模数为质数的时候, (b^{m-2}) 为b模m的乘法逆元。

    如果只是保证b,m互质,那么可以通过求解同余方程 (b*x equiv 1 (mod m)) 得到b的模m的乘法逆元x,可以用扩展欧几里得算法解。
    因为

    [b*x equiv 1 (mod m) ]

    所以

    [b*x -1 equiv 0 (mod m) \ b*x-1是m的倍数,不妨设为-y倍 \ 则有 \ b*x-1=-y*m \ b*x+y*m=1 \ 若b,m互质.则gcd(b,m)=1 ]

    通过求解上面的方程,可以求得一组x,y。x则为b模m的逆元
    下面是模板

    费马小定理求逆元
    inline lxl Quick_Pow(lxl a, lxl b,lxl mod) {
    	lxl res(1 % mod);
            a%=mod;//保险起见
    	for(; b; b >>= 1) {
    		if(b & 1)
    			res = res * a % mod;
    		a = a * a % mod;
    	}
    	return res % mod;
    }
    
    inline lxl Fermat_inv(lxl a,lxl mod){
    	return Quick_Pow(a,mod-2,mod);
    } 
    
    扩展欧几里得求逆元
    int exgcd(int a, int b, int &x, int &y) {
    	if(!b) {
    		x = 1;
    		y = 0;
    		return a;
    	}
    	int d = exgcd(b, a % b, x, y);
    	int z = x;
    	x = y;
    	y = z - (a / b) * y;
    	return d;
    }
    
    int exgcd_inv(int a){
    	int d,x,y;
    	d=exgcd(a,mod,x,y);
    	return (x%mod+mod)%mod;
    }
    
    

    有了乘法逆元,我们遇到a/b的式子后,可以先a,b各自对模数取模,在计算 $ a*b^{-1} mod m $作为答案(前提是b,p互质或p是质数)

    若是要求1n每个数关于模p的逆元,这时候一个个求就显得比较慢了,下面介绍一种求1n每个数模p的逆元的线性求法
    首先 ,(1^{-1} equiv 1 (mod p))
    然后我们设(p=k*i+r, 0le r <i, 1<i<p)
    所以 (k*i+r equiv 0 (mod p))
    然后两边同乘 (i^{-1},r^{-1}) 得到

    [k*r^{-1}*i^{-1} equiv 0 (mod p) \ i^{-1} equiv -k*r^{-1} (mod p) \ i^{-1} equiv - lfloor frac{p}{i} floor *(p \% i)^{-1} (mod p) ]

    inv[1]=1;
    rep(i,2,n){
    	inv[i]=(mod-[mod/i])*inv[mod%i]%mod;
    }//前面加了mod是为了防止逆元变成负数,而且这样常数也比较小
    

    求特定几个组合数的时候,我们需要求出一些连续的阶乘的逆元,我们也可以做到近线性求法

    [因为 frac{1}{n!} = frac {1} {(n+1)!} imes (n+1) ]

    所以我们可以得到以下做法

    fac[0] = 1;//规定0!=1
    rep(i, 1, n) {
    	fac[i] = (fac[i - 1] * i) % mod;
    }
    inv_fac[MAX] = Fermat_inv(fac[n], mod );
    drp(i, n - 1, 0) {
    	inv_fac[i] = inv_fac[i + 1] * (i + 1) % mod;
    }
    

    小技巧
    求$ frac{a}{b} (mod p ) $ 如果 p * b 不会爆掉,可以写成 $$ frac{ a mod (b imes q) } {b} (mod p) $$
    适用于任何情况下。没有逆元可以这样用

    多项式求逆元

    本文来自博客园,作者:{2519},转载请注明原文链接:https://www.cnblogs.com/QQ2519/p/15080819.html

  • 相关阅读:
    如何简单实现一个react组件
    css实现弹框
    flex实现流式布局
    classnames的简单使用
    css处理内容溢出
    webpack学习
    github+hexo搭建,运行hexo g报错
    (附代码和截图)spring基于注解的java定时任务功能实现
    关于Cookie、session和localStorage、以及sessionStorage之间的区别和联系,超详细
    今天向大家推荐一个很强的编辑器——notepad++,没有插件plugin Manager的解决办法
  • 原文地址:https://www.cnblogs.com/QQ2519/p/15080819.html
Copyright © 2020-2023  润新知