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 \leq n \leq 3 \times 10 ^ 6, n < p < 200005281n3×106,n<p<20000528

输入保证 pp 为质数。

 

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

namespace Exgcd
{
    int n,mod,x,y;
    
    void exgcd(int a,int b,int &x,int &y)
    {
        if(b==0)
        {
            x=1,y=0;
            return;
        }
        exgcd(b,a%b,y,x);//回代
        y-=a/b*x;
    }
    
    void work()
    {
        scanf("%d%d",&n,&mod);//求n关于mod的逆元
        exgcd(n,mod,x,y);
        printf("%d\n",(x+mod)%mod);
    }
}

namespace Euler_Fermat
{
    /*————————费马小定理(模数为素数)    O(log n)———————— 
    
    在p是素数的情况下,对任意整数x都有x^p≡x(mod p)。
    如果x无法被p整除,则有x^(p-1)≡1(modp)。
    可以在p为素数的情况下求出一个数的逆元,x*x(p-2)≡1(mod p),x(p-2)即为逆元。
    在模为素数p的情况下,有费马小定理
    a^(p-1)=1(mod p)
    那么a^(p-2)=a^-1(mod p)
    也就是说a的逆元为a^(p-2)
    
    而在模不为素数p的情况下,有欧拉定理
    a^phi(m)=1(mod m)
    同理a^-1=a^(phi(m)-1)
    
    因此逆元x便可以套用快速幂求得了x=a^(phi(m)-1)
    
    若已知p为素数,则直接快速幂求逆元x=a^p-2,
    否则求出a的phi值,快速幂求逆元x=a^(phi-1) 
    
    */
    
    int n,mod;
    
    int euler_phi(int n)
    {
        int res=n;
        for(int i=2;i*i<=n;i++)
        {
            if(n%i==0)
            {
                res=res/i*(i-1);
                while(n%i==0)
                    n/=i;
            }
        }
        if(n!=1)
            res=res/n*(n-1);
        return res;
    }
    
    int ksm(int n,int k)
    {
        int ans=1,tmp=n;
        while(k)
        {
            if(k&1) ans=ans*tmp,ans%=mod;
            tmp*=tmp,tmp%=mod;
            k>>=1;
        }
        return ans;
    }
    
    void work()
    {
        scanf("%d%d",&n,&mod);
        printf("%d\n",ksm(n,mod-2));    //p为素数 
        int phi=euler_phi(mod);    //求phi值 
        printf("%d\n",ksm(n,phi-1));
    }
}

namespace Recursion
{
    /*——————————O(n)求逆元表    模数为素数———————— 
    
    有时会遇到这样一种问题,
    在模质数p下,求1~n逆元 n< p
    
    这个问题有种很牛的算法,其基于以下的推导:
    在求i的逆元时
    p%i+[p/i]*i=p
    令a=p%i,b=[p/i],则有
    a+b*i=p
    a+b*i=0(mod p)
    b*i=-a(mod p)
    i^-1=-b/a
    也就是说i的逆元为:-[p/i]*(p%i)^-1
    而p%i<i,那么可以从2递推到n求逆元,在求i之前p%i一定已经求出
    这样就可以O(n)求出所有逆元了 

    */
    
    const int N=3000005;
    
    int n,mod;
    int inv[N];
    
    void work()
    {
        scanf("%d%d",&n,&mod);
        inv[1]=1;
        for(int i=2;i<=n;++i)
            inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod;
        for(int i=1;i<=n;++i)
            printf("%d\n",inv[i]);
    }
    
}

int main()
{
    Exgcd::work();
    Euler_Fermat::work();
    Recursion::work();
}

 

posted @ 2018-04-08 08:07  whymhe  阅读(357)  评论(0编辑  收藏  举报