模板乘法逆元
Posted yufenglin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模板乘法逆元相关的知识,希望对你有一定的参考价值。
题目背景
这是一道模板题
题目描述
给定n,p求1~n中所有整数在模p意义下的乘法逆元。
输入输出格式
输入格式:
一行n,p
输出格式:
n行,第i行表示i在模p意义下的逆元。
输入输出样例
说明
1≤n≤3×106,n<p<20000528
输入保证 p 为质数。
关于这道题,其实就是一个求逆元的模板题,常见的有三种方法,在这里只介绍两种方法:
1.费马小定理+快速幂(能水64分)
费马小定理:若p为素数,a为正整数,且a、p互质。 则有a^(p−1)≡1(mod p)
又因为a*a的逆元(w)等于1,所以a^(p−1)≡a*w(mod p)
故w在模p意义下是等于a^(p-2)的(记住就好)
所以问题就转化成了求a^(p-2),我们就联想到了快速幂(如果不知道什么是快速幂,我也没招)
这个算法由于快速幂的优化,时间复杂度还是比较可观的,基本可以稳定在(nlogn)
附上该方法的代码:
1 #include<cstdio> 2 using namespace std; 3 long long p; 4 long long qpow(long long x,long long y) 5 { 6 long long ans=1; 7 while(y!=0) 8 { 9 if(y&1) 10 { 11 ans=((ans%p)*(x%p))%p; 12 } 13 x=((x%p)*(x%p))%p; 14 y>>=1; 15 } 16 return ans; 17 } 18 int main() 19 { 20 long long n; 21 scanf("%lld%lld",&n,&p); 22 for(register int i=1;i<=n;i++) 23 { 24 printf("%lld ",(qpow(i,p-2))%p); 25 } 26 return 0; 27 }
2.线性递推(100分O(n)的神级算法)
令 p=ki+r k=⌊p/i?⌋,r=p mod i (i<p,k<p,r<i)
那么显然 ki+r≡0(mod p)
我们将左右同时乘以i和r的逆元即可得到
k∗r^−1+i^−1≡0(modp)
i^−1≡−k∗r^−1(modp)
代入k和r
i^−1≡−⌊p/i⌋∗(p mod i)^-1 (modp)
由于逆元一定是整数,那么我们在等式左右同时乘以(p mod i)^-1倍的p,由于在模p意义下,等式依然成立
最终状态:
inv[i] = (p - p / i) * inv[p % i] % p;(inv指逆元)
附上本算法的代码:
1 #include<cstdio> 2 using namespace std; 3 long long p,c[3000005]; 4 int main() 5 { 6 long long n; 7 scanf("%lld%lld",&n,&p); 8 c[1]=1; 9 printf("1 "); 10 for(register int i=2; i<=n; i++) 11 { 12 c[i]=(p-p/i)*c[p%i]%p; 13 printf("%lld ",c[i]); 14 } 15 return 0; 16 }
以上是关于模板乘法逆元的主要内容,如果未能解决你的问题,请参考以下文章