费马小定理 求乘法逆元
Posted akioi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了费马小定理 求乘法逆元相关的知识,希望对你有一定的参考价值。
//P3811 【模板】乘法逆元 #include<bits/stdc++.h> using namespace std; inline void write(long long X) { if(X<0) {X=~(X-1); putchar(‘-‘);} if(X>9) write(X/10); putchar(X%10+‘0‘); } long long qpow(long long n,long long m,long long mod) { long long ans=1; while(m) { if(m&1) ans=ans*n%mod; n=n*n%mod; m>>=1; } return ans%mod; } int main() { long long n,p; scanf("%lld%lld",&n,&p); for(long long i=1;i<=n;i++) write(qpow(i,p-2,p)),printf(" "); return 0; }
这一道题是洛谷P3811 【模板】乘法逆元
当然这一道题用费马小定理还是过不去的
不过可以证明这一做法的正确性
首先我们要保证题目给出的p是质数
所谓费马小定理就是
a^(p-1) ≡ 1 (mod p)
稍加化简就可以看出左边可以化为a*a^(p-2)
把那个单独的a挪到右边
所以a^(p-2)=a-1
也就是a^(p-2)就是a在模p意义下的乘法逆元
然而我们可以用快速幂来进行加速
这样一来算出一个乘法逆元的时间复杂度就是logn
但是一定要注意 必须p是负数!
上线性筛
//P3811 【模板】乘法逆元 #include<bits/stdc++.h> using namespace std; inline void write(long long X) { if(X<0) {X=~(X-1); putchar(‘-‘);} if(X>9) write(X/10); putchar(X%10+‘0‘); } long long qpow(long long n,long long m,long long mod) { long long ans=1; while(m) { if(m&1) ans=ans*n%mod; n=n*n%mod; m>>=1; } return ans%mod; } long long inv[3000005]; int main() { long long n,p; scanf("%lld%lld",&n,&p); // for(long long i=1;i<=n;i++) // write(qpow(i,p-2,p)),printf(" "); inv[1]=1;write(1),printf(" "); for(int i=2;i<=n;i++) inv[i]=(p-p/i)*inv[p%i]%p,write(inv[i]),printf(" ");//线性筛 return 0; }
还有一个需要注意的地方
就是那个取模运算是很耗时间的
一开始我把代码改成线性筛之后
在输出 就是那个write的括号里又增加了一个%p
事实上是没有必要的
结果就因为这个多余的取模 y以至于我还是T一个点,,
所以千万不要多加太多%取模
以上是关于费马小定理 求乘法逆元的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ_[HNOI2008]_Cards_(置换+Burnside引理+乘法逆元+费马小定理+快速幂)
[CodeVs1515]跳(lucas定理+费马小定理+乘法逆元)