[模板]乘法逆元

本博客所有代码基于题目 luogu_P3811

逆元:

  一般用于求 (a/b) mod p 

定义:

  若 a*≡ (mod p) ,且 a 与 p 互质,那么我们就能定义: 为 的逆元,记为 a^-1 ,所以我们也可以称 x 为 a 的倒数(mod p意义下)。

  所以对于 (a/b) mod p ,我们就可以求出 b 在 mod p 意义下的逆元,然后乘上 a ,再 mod p ,就是这个乘法逆元的值了。

求法:

First:费马小定理

定理内容:如果 互质,那么 a^(p-1) ≡ 1 (mod p)

  结合逆元方程 a*x ≡ 1 (mod p) ,得到 a*x ≡ a^(p-1)  (mod p)
  根据同余的性质,若p为质数,得到 x ≡ a^(p-2)  (mod p)
  即 x = a^(p-2) mod p, 快速幂 求解即可

Second:欧拉定理

定理内容:如果a,p互质,那么a^φ(p) ≡ 1 (mod p),当 为质数时,φ(p)=p-1

  同理,结合同余方程,得 x=a^(p-2) mod p,快速幂求解即可

  (这只是两种不同的证明,代码是相同的)

 1 #include<cstdio>
 2 #define ll long long
 3 using namespace std;
 4 int n,p;
 5 inline ll ksm(ll a,ll b){
 6     ll ans=1;
 7     a%=p;
 8     while(b){
 9         if(b&1) ans=ans*a%p;
10         a=a*a%p;
11         b>>=1;
12     }
13     return ans%p;
14 }
15 void write(ll x){
16     if(x<0) putchar(‘-‘),x=-x;
17     if(x>9) write(x/10);putchar(x%10^48);
18 }
19 int main(){
20     scanf("%d%d",&n,&p);
21     for(int i=1;i<=n;i++)
22         write(ksm(i,p-2)),putchar(‘\n‘);
23     return 0;
24 }

TLE_83分

Third:解不定方程

解同余方程 ax≡1 (mod p) 等价于 解不定方程 ax+py=1
Exgcd求解即可(不会 请左转 Exgcd 
由于 是质数,那么gcd(a,p)=1;
即求解不定方程 ax+by=gcd(a,b);

 1 #include<cstdio>
 2 using namespace std;
 3 int x,y;
 4 void exgcd(int a,int b){
 5     if(!b){x=1,y=0;return ;}
 6     exgcd(b,a%b);
 7     int t=x;
 8     x=y,y=t-a/b*y;
 9 }
10 void write(int x){
11     if(x>9) write(x/10);
12     putchar(x%10^48);
13 }
14 int main(){
15     int n,p;
16     scanf("%d%d",&n,&p);
17     for(int i=1;i<=n;++i)
18         exgcd(i,p),write((x%p+p)%p),putchar(‘\n‘);
19     return 0;
20 }

AC_1240ms

Forth:线性递推

复杂度 O(n)
递推过程:
令 p=ki+r ; {k=[p/i] (下取整), r=p mod i } (i<p,k<p,r<i)
则有 ki+r≡0(mod p) 
①式左右同乘i^-1*r^-1 得:
k*r^-1+i^-1 ≡ 0 (mod p)
移项 得
i^-1 ≡ -k*r^-1 (mod p)
带入 k=[p/i] (下取整), r=p mod i;
i^-1 ≡ -[p/i]*(p mod i)^-1 (mod p) 
由于 (p mod i) < i ,所以,在求出 i^-1 之前,我们早已求出 (p mod i)^-1
因此用数组 inv[i] 记录i^-1 的逆元)
则 inv[i]=-p/i*inv[p%i]%p;

不要以为到这里就结束了
因为我们需要保证 i^-1>0
所以,我们在②式右边+p p mod p=0,答案不变)
inv[i]=p-p/i*inv[p%i]%p;
当然 inv[1]=1,inv[0]=tan90°(赋值为0);
而且 for循环 要从 开始,防止改变 inv[1] 的值;
至此,证毕。

 1 #include<cstdio>
 2 #define ll long long
 3 using namespace std;
 4 const int maxn=3e6+5;
 5 ll inv[maxn]={0,1};
 6 int main(){
 7     int n,p;
 8     scanf("%d%d",&n,&p);
 9     printf("1\n");
10     for(int i=2;i<=n;i++)
11         inv[i]=(ll)p-(p/i)*inv[p%i]%p,printf("%d\n",inv[i]);
12     return 0;
13 }

AC_664ms

参考文献:https://www.cnblogs.com/zjp-shadow/p/7773566.html

原文地址:https://www.cnblogs.com/RisingGods/p/9484039.html

时间: 2024-11-09 02:54:25

[模板]乘法逆元的相关文章

Luogu P3811 [模板]乘法逆元 题解报告

题目传送门 [题目大意] 给定$n$,求$1-n$在膜$p$意义下的乘法逆元. [思路分析] 好的原本我只会求单个数的逆元,然后被告知了这道题之后发现自己不会做(我果然还是太弱了),于是就学了一下递推求逆元. 设$p=k*i+r$,则可得$k*i+r\equiv0(mod\ p)$,然后乘上$i^{-1},r^{-1}$即可得到$k*r^{-1}+i^{-1}\equiv0(mod\ p)$ 由于$k=\lfloor \frac{p}{i}\rfloor,r=p\ mod\ i$,所以$i^{-

P3811 【模板】乘法逆元

P3811 [模板]乘法逆元 题目背景 这是一道模板题 题目描述 给定n,p求1~n中所有整数在模p意义下的乘法逆元. 输入输出格式 输入格式: 一行n,p 输出格式: n行,第i行表示i在模p意义下的逆元. 输入输出样例 输入样例#1: 10 13 输出样例#1: 1 7 9 10 8 11 2 5 3 4 说明 1≤n≤3×10?6??,n<p<20000528 输入保证 p 为质数. 我们有三种办法求逆元 由欧拉定理可知 当gcd(a,n)==1 时 我们有 Aφ(n-1)≡ 1(mod

洛谷 P3811 【模板】乘法逆元 如题

P3811 [模板]乘法逆元 时空限制1s / 256MB 题目背景 这是一道模板题 题目描述 给定n,p求1~n中所有整数在模p意义下的乘法逆元. 输入输出格式 输入格式: 一行n,p 输出格式: n行,第i行表示i在模p意义下的逆元. 输入输出样例 输入样例#1: 10 13 输出样例#1: 1 7 9 10 8 11 2 5 3 4 说明 1 \leq n \leq 3 \times 10 ^ 6, n < p < 200005281≤n≤3×106,n<p<20000528

题解 P3811 【模板】乘法逆元

题意求\(i\)在模\(p\)意义下的逆元\(\frac{1}{i}\)即\(inv(i)\).题目数据范围很明显规定了要求一个线性求逆元的算法. 令\(p=ai+b\),则有: \[ai+b\equiv 0(\mod p)\] 移项得: \[ai\equiv -b(\mod p)\] 系数化简得: \[i\equiv -\frac{b}{a}(\mod p)\] 取倒数得: \[\frac{1}{i} \equiv -\frac{a}{b}(\mod p)\] 即 \[inv(i) \equi

[洛谷P3811]【模板】乘法逆元

题目大意:给你n和质数p,求1~n在模p意义下的乘法逆元(n<p). 解题思路:由于$n<p<20000528$,所以扩展欧几里得是会超时的.这儿就要用到线性推逆元大法辣!→不懂戳这里← 注意乘法可能会超过int,所以计算时先转化为long long即可. C++ Code: #include<cstdio> int n,p,inv[20000529]; int main(){ scanf("%d%d",&n,&p); puts("

【模板】求1~n的整数的乘法逆元

洛谷3811 先用n!p-2求出n!的乘法逆元 因为有(i-1)!-1=i!-1*i (mod p),于是我们可以O(n)求出i!-1 再用i!-1*(i-1)!=i-1 (mod p)即是答案 1 #include<iostream> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cstdio> 5 #include<cmath> 6 #include<algorithm> 7

T106021 【模板】乘法逆元(快速幂)

题目地址 注意点: 使用exgcd求乘法逆元需额外进行(相对)较多操作,建议使用快速幂求乘法逆元. #include<cstdio> #include<iostream> #define ll long long using namespace std; int n,p; int poww(int a,int b){ ll ans=1,tmp=a; while(b){ if(b&1){ ans*=tmp; ans%=p; } tmp=tmp*tmp; tmp%=p; b&g

乘法逆元(模板)

乘法逆元定义: b存在乘法逆元的充要条件是b与模数m互质 原因:b * x ≡ 1 (mod m) 如果b和m不互质,则 b * x肯定是m的倍数,b * x%m=0  所以b%m==0 ,b不存在乘法逆元 1.当n为质数时,可以用快速幂求逆元: a / b(整除) ≡ a * x (mod m) 两边同乘b可得 a ≡ a * b * x (mod m) -> 1 ≡ b * x (mod m) 同 b * x ≡ 1 (mod m) 由费马小定理可知,当m为质数时:  b ^ (m - 1)

loj #110. 乘法逆元

#110. 乘法逆元 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 这是一道模板题. 给定正整数 n nn 与 p pp,求 1∼n 1 \sim n1∼n 中的所有数在模 p pp 意义下的乘法逆元. 输入格式 一行两个正整数 n nn 与 p pp 输出格式 n nn 行,第 i ii 行一个正整数,表示 i ii 在模 p pp 意义下的乘法逆元. 样例 样例输入 10 13 样例输出