线性求乘法逆元

乘法逆元出门跳坑

欧拉函数证明出门打的

欧拉函数代码实现出门小黄车

许多题会用到乘法逆元这个玄学的东西,求一次还好,但是如果求1~p-1在mod p意义下的逆元,单个求的log级别显然不可取,所以我门需要线性处理一下

先说几个单个求的思路

方法一:先预处理欧拉函数,然后用快速幂求a^(φ(p)-1)

代码(线性欧拉函数)

void getphi()    
{    
   int vis[M],phi[M],pri[M],tot;   
   for(int i=2;i<=n;i++)   
   {    
     	if(!vis[i])//先判断i是不是素数    
    	{    
            pri[++tot]=i; 
            phi[i]=i-1;//当 i 是素数时小于i的所有大于零的数都和i互素    
        }    
       	for(int k=1;k<=tot;k++)    
       	{    
          	if(i*pri[k]>M)  break;    
          	vis[i*pri[k]]=1;//按照筛素数,筛掉i的倍数 
          	if(i%pri[k]==0)//如果有一个质数是i的因子,那么phi(i*pri[k])=phi(i)*pri[k]  
          	{    
             	phi[i*pri[k]]=phi[i]*pri[k];break;    
          	}    
          	else  phi[i*pri[k]]=phi[i]*(phi[pri[k]]);
			  //利用了欧拉函数的积性,两个数互质,那么phi(i*k)=phi(i)*phi(pri[k])   
       	}    
   }    
}    
//快速幂自己写吧我就不放了

方法二:扩展欧几里得,将同余式转化为a*x+p*y=1,求解x,y

代码

//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int x,y,n,m;
int exgcd(int a,int b,int &x,int &y)
{
    if (b==0) 
    {
        x=1;y=0;return a;	
    }	
    else
    {
        int d=exgcd(b,a%b,x,y);
        int z=x;x=y;y=z-y*(a/b);
        return d;
    }
} 
int main()
{
    scanf("%d%d",&n,&m);
    exgcd(n,m,x,y);
    cout<<(x%m+m)%m; 
    return 0;
}

方法三:o(n)求逆元表,没错就是打表(通过递推打表)

假如要求i在mod p意义下的逆元,我们令a=p%i,b=(p/i),则p=a+b*i,可得a+b*i ≡ 0 (mod p),则-a ≡ b*i (mod p),则i^(-1)≡-(b/a) (mod p),所以可得i的乘法逆元=-(p/i)*(p%i)^(-1),则可以递推得到所有逆元,因为p%i必定小于i,所以在处理i之前必定已经处理好了p%i

代码

void mutl(int mod)
{
	int inv[M];inv[1]=1;//边界条件 
	for (int i=2;i<=M;i++) 
		inv[i]=((-(mod/i)*inv[mod%i])%mod+mod)%mod; //防止出现负数 
	return ; 
} 
如有错误请联系博主



猜你喜欢

转载自blog.csdn.net/ACerAndAKer/article/details/80724198