22°

费马小定理 求乘法逆元

//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("\n");
    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("\n");
    inv[1]=1;write(1),printf("\n");
    for(int i=2;i<=n;i++)
    inv[i]=(p-p/i)*inv[p%i]%p,write(inv[i]),printf("\n");//线性筛 
    return 0;
}

 

还有一个需要注意的地方

就是那个取模运算是很耗时间的

一开始我把代码改成线性筛之后 

在输出 就是那个write的括号里又增加了一个%p

事实上是没有必要的

结果就因为这个多余的取模 y以至于我还是T一个点,,

所以千万不要多加太多%取模

本文转载自博客园,原文链接:https://www.cnblogs.com/akioi/p/12207274.html

全部评论: 0

    我有话说: