许多题会用到乘法逆元这个玄学的东西,求一次还好,但是如果求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 ; }如有错误请联系博主