a,x,p均为正整数,p是质数,a*x≡1(mod p)
给出a,p求最小的符合条件的x(也就是a的逆元,a-1(mod p))。
法一:快速幂 O(log p)
根据费马小定理可得 a*ap-2=ap-1≡1(mod p),此时a-1≡ap-2 (mod p)。用快速幂求即可。
1 int p,x=1,w,a,xx; 2 w=p-2; 3 xx=a; 4 while(w){ 5 if(w&1)a*=xx,a%=p; 6 xx*=xx;xx%=p; 7 w/=2; 8 }
法二:扩展欧几里德(不要求p是质数,只要求a,p互质) O(log a)
我们知道,扩展欧几里得可以求给定正整数a,b的关于整数x,y的不定方程 a*x+b*y=gcd(a,b)的某一组解。
此时,只要将该方程写作a*x+p*y=1并求出x即可。
1 void exgcd(int a,int b,int &x,int &y){//对a,b求逆元,注意勿省略&,修改的是x,y本身而不是传递的值 2 if(b==0){ 3 x=1; 4 y=0; 5 return ; 6 } 7 gcd(b,a%b,y,x); 8 y-=x*(a/b); 9 }
法三:线性求逆元 O(a)
这种方法比较适用于求1~a对某一p的逆元。
若 p÷a=k…r。
则有 a*k+r≡0(mod p) k+r*a-1≡0(mod p) a-1≡-k*r-1(mod p)
代码也比较好写。
1 const int sz=1e6+5; 2 int a,p,x[sz];//x[i]表示i的逆元 3 x[1]=1; 4 for(int i=2;i<=a;i++)x[i]=-(p/i)*x[p%i],x[i]=(x[i]%p+p)%p;
法四:法三的……优化?(对于求单个数的逆元来说算是吧……) O(log a)
其实以上三个方法都比较容易找到,写这篇博客的真正目的是在书上看见了法四,想分享一下。
对于法三,其实求每个a的逆元,只要求出(p%a)的逆元即可。则可以递归地去做。