P3811 【模板】乘法逆元
题目背景
这是一道模板题
题目描述
给定n,p求1~n中所有整数在模p意义下的乘法逆元。
输入输出格式
输入格式:
一行n,p
输出格式:
n行,第i行表示i在模p意义下的逆元。
输入输出样例
说明
1 \leq n \leq 3 \times 10 ^ 6, n < p < 200005281≤n≤3×106,n<p<20000528
输入保证 pp 为质数。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; namespace Exgcd { int n,mod,x,y; void exgcd(int a,int b,int &x,int &y) { if(b==0) { x=1,y=0; return; } exgcd(b,a%b,y,x);//回代 y-=a/b*x; } void work() { scanf("%d%d",&n,&mod);//求n关于mod的逆元 exgcd(n,mod,x,y); printf("%d\n",(x+mod)%mod); } } namespace Euler_Fermat { /*————————费马小定理(模数为素数) O(log n)———————— 在p是素数的情况下,对任意整数x都有x^p≡x(mod p)。 如果x无法被p整除,则有x^(p-1)≡1(modp)。 可以在p为素数的情况下求出一个数的逆元,x*x(p-2)≡1(mod p),x(p-2)即为逆元。 在模为素数p的情况下,有费马小定理 a^(p-1)=1(mod p) 那么a^(p-2)=a^-1(mod p) 也就是说a的逆元为a^(p-2) 而在模不为素数p的情况下,有欧拉定理 a^phi(m)=1(mod m) 同理a^-1=a^(phi(m)-1) 因此逆元x便可以套用快速幂求得了x=a^(phi(m)-1) 若已知p为素数,则直接快速幂求逆元x=a^p-2, 否则求出a的phi值,快速幂求逆元x=a^(phi-1) */ int n,mod; int euler_phi(int n) { int res=n; for(int i=2;i*i<=n;i++) { if(n%i==0) { res=res/i*(i-1); while(n%i==0) n/=i; } } if(n!=1) res=res/n*(n-1); return res; } int ksm(int n,int k) { int ans=1,tmp=n; while(k) { if(k&1) ans=ans*tmp,ans%=mod; tmp*=tmp,tmp%=mod; k>>=1; } return ans; } void work() { scanf("%d%d",&n,&mod); printf("%d\n",ksm(n,mod-2)); //p为素数 int phi=euler_phi(mod); //求phi值 printf("%d\n",ksm(n,phi-1)); } } namespace Recursion { /*——————————O(n)求逆元表 模数为素数———————— 有时会遇到这样一种问题, 在模质数p下,求1~n逆元 n< p 这个问题有种很牛的算法,其基于以下的推导: 在求i的逆元时 p%i+[p/i]*i=p 令a=p%i,b=[p/i],则有 a+b*i=p a+b*i=0(mod p) b*i=-a(mod p) i^-1=-b/a 也就是说i的逆元为:-[p/i]*(p%i)^-1 而p%i<i,那么可以从2递推到n求逆元,在求i之前p%i一定已经求出 这样就可以O(n)求出所有逆元了 */ const int N=3000005; int n,mod; int inv[N]; void work() { scanf("%d%d",&n,&mod); inv[1]=1; for(int i=2;i<=n;++i) inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod; for(int i=1;i<=n;++i) printf("%d\n",inv[i]); } } int main() { Exgcd::work(); Euler_Fermat::work(); Recursion::work(); }