/ * 以下皆是关于模板的理解,数学证明略 * /
一、 逆元的用处:
求(a / b)% p
运算符 (加 、减 、 乘 ) 可以利用分配律来求解。但除法却不可以。
——逆元的作用:可把除法转化为乘法。
简单理解:就是求b的倒数,但1 / b 显然是小数,不是想要的结果,想办法变为整数,即求b关于p的逆元。
——现在只看 b 和 p,跟 a 没关系。
什么情况下才可以 b 关于 p 求逆元呢?
——只有当gcd(b,p)==1时,逆元才存在。
咋求:
第一种情况(特例):p是质数。
费马小定理:逆元=Qmod(b,p-2,p)。
注:Qmod为快速幂取模。
第二种情况:p不是质数,但gcd(b,p)==1。
方法1:求出 p 的欧拉函数值,逆元=Qmod(b,Euler(p)- 1,p)
方法2:利用扩展欧几里得求解。ax+by=gcd(a,b)。
二、 扩展欧几里得求逆元
注意:extend_gcd函数求解的x,y是对于下面的方式而言的
ax+by=gcd(a,b)
而不是ax+by=c
如何求x,y
首先了解最大公因数递归法
int gcd(int a,int b) {return b==0?a:gcd(b,a%b);}
然后extend_gcd函数,其就是在gcd函数基础上加一点点东西
看板子:求b关于p的逆元。
ll extend_gcd(ll a,ll b,ll &x,ll &y)
{
if(a==0&&b==0) return -1;//不求逆元该句不加
if(b==0){
x=1,y=0;
return a;
}
ll r=extend_gcd(b,a%b,x,y);
ll t=y;
y=x-(a/b)*y;
x=t;
return r;
/*上面五行可换下面三行,一样的,如何转化的往下看
ll r=extend_gcd(b,a%b,y,x);
y-=a/b*x;
return r;
*/
}
//求b关于p的逆元
ll inv(ll b,ll p){
ll x,y;
ll r=extend_gcd(b,p,x,y);
if(r==1)
return (x%p+p)%p;//保证得到的x是最小的非负数
else
return -1;
}
x,y是如何转化的,点这里。
但 x 为什么可作为逆元,作者自己也不清楚。
逆元例题:
A/B HDU - 1576
逆元 计蒜客 - T3126
乘法逆元 LibreOJ - 110
乘法逆元 2 LibreOJ - 161