若整数\(b,m\)互质,且\(b|a\),则存在一个整数,使得\(a/b\equiv a\times k(\mod m)\),称\(k\)为\(b\)的模\(m\)乘法逆元,记作
\[b^{-1}(\mod m)\]
快速计算\(k\)
数据范围:
\(1\le b\le 3\times 10^{6}\)
\(b\le m\le 20000528\)
要快速求解\(k\),暴力肯定不行的。
题中指出:\(b,m\)互质,
那么,根据欧拉定理:\(b^{\varphi(m)}\equiv 1(\mod m)\),所以:
\[\therefore b^{\varphi(m)-1}\times b^{1}\equiv 1(\mod m)\]
\[\therefore b^{\varphi(m)-1}\equiv b^{-1}(\mod m)\]
\[\therefore k=b^{\varphi(m)-1}\mod m\]
\(\varphi(m)\)可以在\(O(\sqrt{m})\)的时间内算出。若\(m\)为质数,那么\(\varphi(m)\)就\(=m-1\)。
再使用快速幂便可以在\(\log_2\)复杂度级别快速算出。
插入:\(b,m\)必定互质
\(\text{证明:}\)
反证法。
假设\(g=\gcd(b,m)\),且\(g\ne 1\)。
将原式化为:\(b\times k\equiv 1(\mod m)\)。
\[\because g|b,\therefore g|(b\times k)\]
而原式中:
\[b\times k \mod m=1\]
可见原命题中的\((b\times k),m\)一定互质。
而假设中\(g\ne 1\),所以假设不成立。
\(\therefore\) \(b,m\)必定互质。
证毕。
完全积性函数
(以下用\(inv[i]\)不上\(i\)在\((\mod m)\)的意义下的乘法逆元)
即:
\[inv[a]\times inv[b]\equiv inv[a\times b](\mod m)\]
证明:
\[a\times inv[a]\equiv b\times inv[b]\equiv 1(\mod m)\]
\[\therefore (a\times b)\times(inv[a]\times inv[b])\equiv 1(\mod m)\]
\[\therefore(inv[a]\times inv[b])\text{即为}(a\times b)\text{的逆元}\]
\[\therefore inv[a]\times inv[b] \equiv inv[a\times b]\]
拓展:\(b\times k\equiv h(\mod m)\)的最小正整数解
其实原理是一样的。
同样的,欧拉定理:\(b^{\varphi(m)}\equiv 1(\mod m)\)
\[\therefore b^{\varphi(m)-1}\times b\equiv 1(\mod m)\]
\[\therefore b^{\varphi(m)-1}\equiv b^{-1}(\mod m)\]
两边同时\(\times h\),得:
\[b^{\varphi(m)-1}\times h\equiv \frac{h}{b}(\mod m)\]
\[b^{\varphi(m)-1}\times h\text{即为我们要求的k的值。}\]
在线性时间快速求出\(1-n\)的乘法逆元
也就是这道题:luogu P3811 【模板】乘法逆元
用上述的算法逐个求解会爆炸,所以我们需要一个更优的算法。
引入:
做这道题之前,我们先看一个这样的问题:
求\(inv[1!],inv[2!],inv[3!],...,inv[(n-1)!],inv[n!]\)(\(inv[i]\)指的\(i(\mod m)\)的意义下的乘法逆元)
首先,我们求出\(1!,2!,3!,...,(n-1)!,n!(\mod m)\)。
因为有如下递推关系:
\[inv[i!]=\dfrac{1}{i!}\]
\[inv[i!]\times i=\dfrac{1}{i!}\times i=\dfrac{1}{(i-1)!}=inv[(i-1)!]\]
所以,我们只要求出\(inv[n!]\),就可以\(O(n)\)逆推出所有阶乘的逆元了。
递推式:
\[inv[i!]=inv[(i+1)!]\times (i+1)!\]
回到此题:
通过\(1-n\)阶乘的逆元,我们可以快速推出:
\[inv[i]=\dfrac{1}{i}=\dfrac{(i-1)!}{i!}(\mod p)\]
Code(Luogu P3811):
#include<cstdio>
using namespace std;
const int N=3e6+15;
typedef long long ll;
int inv[N];
int fac[N];
int rf[N];//inv of fac
int n,p;
int pow(int b,int i)
{
if(!i)return 1;
if(i==1)return b;
if(i%2)
{
int tmp=pow(b,i/2)%p;
return ((ll)(tmp)*tmp%p*b)%p;
}
else
{
int tmp=pow(b,i/2)%p;
return ((ll)(tmp)*tmp)%p;
}
}
signed main()
{
register int i;
scanf("%d%d",&n,&p);
fac[0]=1;
for(i=1;i<=n;i++)
fac[i]=(ll)(fac[i-1])*i%p;
rf[n]=pow(fac[n],p-2)%p;
for(i=n-1;i>=1;i--)
rf[i]=(ll)(rf[i+1])*(i+1)%p;
inv[1]=1;
for(i=1;i<n;i++)
inv[i+1]=(ll)(rf[i+1])*fac[i]%p;
for(i=1;i<=n;i++)
printf("%d\n",inv[i]);
return 0;
}