您的位置:首页 > 其它

[模板]乘法逆元

2017-11-09 20:36 162 查看

费马小定理

适用:求某一个数在模意义下的乘法逆元。

如果a、p互质,那么有ap−a就是p的倍数,所以有ap≡a(modp),ap−1≡1(modp)。所以只要打一个快速幂就ok了。

code

#include<bits/stdc++.h>
using namespace std;
int n,p;
int power(int x,int k)
{
int ans=1;
while(k)
{
if(k&1)ans*=x%p;
ans%=p;
x=x*x%p;
k>>=1;
}
return ans%p;
}
int main()
{
scanf("%d%d",&n,&p);
printf("1\n");
for(int i=2;i<=n;i++)
printf("%d\n",power(i,p-2));
return 0;
}


线性求法

适用:某一区间的所有的数在模意义下的乘法逆元、求单个逆元(递归求解)。

简单地说就是一个递推。

首先我们有:1−1≡1(modp)

然后,我们设p=k×i+r,r<l,1<i<p再将这个式子放到modp意义下一看:k×i+r≡0(modp)

再两边同时乘上i−1,r−1可以得到:

k×r−1+i−1≡0(modp)

移项:

i−1=−k×r−1(modp)

所以:

i−1≡−[pi]×(pmodi)−1

于是乎我们就可以递推处当前的逆元了:

A[i]=-(p/i)*A[p%i]


然后其实吧,我们还可以通过递归求解,在O(log2p)的时间内求出单个逆元。怎么证明时间复杂度呢:由于我们可以发现pmodi<i/2,所以每次的子问题规模减半,最终递归次数也可见了。

code:

#include<bits/stdc++.h>
#define maxn 3000005
using namespace std;
int n;
long long p;
long long ans[maxn];
int main()
{
scanf("%d%lld",&n,&p);
ans[1]=1;
for(int i=2;i<=n;i++)
ans[i]=(-(p/i)*ans[p%i])%p;
for(int i=1;i<=n;i++)
printf("%lld\n",ans[i]>0 ? ans[i] : ans[i]+p);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: