• 逆元的各种姿势



    %还得写个反斜杠,好烦人

    update 11.1

    get新技能
    求阶乘的逆元 ,注意只是阶乘的逆元
    也是线性的

    inv[n] = f_pow(jc[n],mod - 2); 
    	for(int i = n;i >= 1;-- i) inv[i-1] = inv[i] * i % mod; 
    

    扩展欧几里得求逆元

    (a*a^{-1}≡1(mod p))
    即求 $$aa^{-1}+kp=1(mod p)$$
    因为
    p是质数,(a<p)

    所以 (gcd(a,p)=1)
    进一步转化为(a*a^{-1}+k*p=gcd(a,p))
    恰好的,(exgcd)在求解(gcd)的时候正好可以求出一组解(x,y)解得的(x)即为(4a)(%p)意义下的逆元
    复杂度就当做O(logn)吧

    附带(exgcd)的证明
    求解(a*x+b*y=gcd(a,b))的一组解

    由辗转相除法容易知道
    (gcd(a,b)=gcd(b,a\%b))
    所以
    (b*x+a\%b*y=gcd(b,a\%b))

    (a*x+b*y=gcd(a,b))
    是相等的
    (a*x+b*y=b*x+a\%b*y)
    (a\%b=a-[a/b]*b)
    (a*x+b*y=b*x+(a-a/b*b)*y)
    去括号
    (a*x+b*y=b*x+a*y-[a/b]*b*y)
    结合
    (a*x+b*y=b*x+a*y-[a/b]*b*y)
    (a*x+b*y=a*y+b*(x-[a/b]*y))
    易得
    (x=y)
    (y=x-[a/b]*y)

    void exgcd(int a,int b,int &x,int &y) 
    {
    	if (!b)
    	{
    		x=1;y=0;
    		return;
    	}
    	exgcd(b,a%b,x,y);
    	int tmp=x;
    	x=y;
    	y=tmp-a/b*y;
    }
    int inv_exgcd(int a,int b) 
    {
    	int x,y;
    	exgcd(a,b,x,y);
    	while(x<0) x+=b;
    	return x;
    }
    

    费马小定理求逆元

    前提条件:当p为质数的情况下
    费马小定理
    (a^{p-1}≡1(mod p))
    变形一下
    (a*a^{p-2}≡1(mod p))
    然后我们就很开心的求得了a的逆元啦
    逆元就是(a^{p-2})
    (a)(p-2)次方可以快速幂O(logn)求出

    int f_pow(int a,int b,int p) 
    {
    	int ans=1;
    	while(b) {
    		if(b&1)	ans*=a,ans%=p;
    		a*=a;
    		a%=p;
    		b>>=1;
    	}
    	return ans;
    }
    int inv_feima(int a,int p)
    {
    	return f_pow(a,p-2,p);
    }
    

    线性求逆元

    前提条件:当p为质数的情况下
    线性求逆元,两种方法,这里介绍只一种*
    (那一种求阶乘的在代码量和理解和常数在我感觉下都不如我介绍的优秀,不再介绍)
    (p=k*i+r)
    (k=p/i,r=p\%i)
    (p≡0(mod p))
    (k*i+r≡0(mod p))
    (r≡-k*i(mod p))
    两边同乘(i^{-1},r^{-1}~~是他们两个~~(在mod p意义下))
    得到
    (i^{-1}≡-k*r^{-1}(mod p))
    代入k和r的值
    (i^{-1}≡-p/i*(p\%i)^{-1}(mod p))
    为了求得的逆元是正数,变一下
    (i^{-1}≡(p-p/i)*(p\%i)^{-1}(mod p))
    因为((p\%i)^{-1})在我们之前就求出来了,所以就我们开心的就求出i的逆元啦
    而且代码短

    int inv[1011111];
    void get_inv(int p)
    {
    	inv[0]=inv[1]=1;
    	for(int i=2;i<p;++i)
    		inv[i]=(p-p/i)*inv[p%i]%p;
    }
    

    如果我写错了,欢迎评论提出

  • 相关阅读:
    突破
    leetcode刷题 538~
    leetcode刷题 519~
    Docker练习之镜像更新方法1
    十二 Linux之tar解压缩
    十一 Linux软件包管理yum
    十 Linux指令之grep
    九 linux指令之find
    八 Linux ps指令查看进程和kill杀进程
    七 Linux top命令
  • 原文地址:https://www.cnblogs.com/dsrdsr/p/9503587.html
Copyright © 2020-2023  润新知