费马小定理 求乘法逆元

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定理+费马小定理+乘法逆元)

hdu1576-A/B-(同余定理+乘法逆元+费马小定理+快速幂)

费马小定理及其应用

数论学习之费马与欧拉

HDU - 1576(费马小定理求逆元)