洛谷上的板子 https://www.luogu.org/problem/P3811
乘法逆元,也就是当ax≡1(mod p) 且gcd(a,p)=1时,x为a在mod p下的乘法逆元 注意,乘法逆元有唯一性(跟同余方程不同,此解必须为最小正整数)
可以说x为a 在mod b 意义下的倒数,
(可以求a/b(modp)的值(前求出b在mod p下的逆元,再乘a模p即可))
题目上是求1~n在mod p下的逆元,且n<p , p为质数
就是 ax%p=1
第一种做法——扩展欧几里得
(exgcd的入门 https://www.cnblogs.com/ffrxy01bt/p/11261296.html )
对于每个数暴力用exgcd解决即可 满足exgcd的要求,只需gcd(a,p)=1(当然,不这样的话无解)
时间复杂度:O(nlogn) 由于时间很紧,建议此题不用这个,因为会被卡掉。(虽然它无需要p为质数)
给一个80pts代码
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
#include<map>
using namespace std;
#define re register int
#define int long long
inline int read(){
int x=0,ff=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')ff=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*ff;
}
int x,y,xx,yy;
inline void gcd(int a,int b){
if(b==0){x=1;y=0;return;}
gcd(b,a%b);
xx=x;yy=y;
x=yy;y=(xx-(a/b)*yy);
}
signed main(){
int n=read(),p=read();
for(re i=1;i<=n;i++){
gcd(i,p);
printf("%d\n",(x%p+p)%p);
}
return 0;
}
第二种做法——费马小定理
公式:若p为素数,a为正整数,且a、p互质。 则有a^(p-1) ≡1(mod p)。
这个算法就需要p为质数,且gcd(a,p)=1了
有公式就知道a^(p-1)≡1(mod p) 而求的是 ax%p=1
转换一下 ax%p=a^(p-1)%p x=a^(p-2)%p
所以,一个快速幂也解决了 时间复杂度同样是O(nlogn)
洛谷上只有64pts
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
#include<map>
using namespace std;
#define re register int
#define int long long
inline int read(){
int x=0,ff=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')ff=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*ff;
}
inline int qsm(int x,int y,int p){
int s=1;
while(y){if(y&1)s=s*x%p;x=x*x%p;y>>=1;}
return s;
}
signed main(){
int n=read(),p=read();
for(re i=1;i<=n;i++){
printf("%d\n",(qsm(i,p-2,p)+p)%p);
}
return 0;
}
线性递推
这就是本题的正解了
首先,我们一定能都得到1在mod p下,逆元为1
再加设yi+z=p(i为数i,y为int(p/i),z为p%i) 再假设f[i]表示f[i]为关于i在mod p下的逆元
那么 (yi+z)≡0(mod p) -z≡yi(mod p) 同乘上f[i]f[z]后 则 -f[i]≡y*f[z] (mod p) 所以 f[i]=-(p/i)f[p%i]%p
然后就是程序了
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
#include<map>
using namespace std;
#define re register int
#define int long long
inline int read(){
int x=0,ff=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')ff=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*ff;
}
int f[3000005];
signed main(){
int n=read(),p=read();f[1]=1;printf("1\n");
for(re i=2;i<=n;i++){
f[i]=(-(p/i)*f[p%i]%p+p)%p;
printf("%d\n",f[i]);
}
return 0;
}
时间复杂度是O(n)的,但是必须要p为质数,且gcd(a,p)=1
但愿考试遇到的都很水,直接套exgcd就能过