乘法逆元

乘法逆元

定义

对于一个线性同余方程 ax1(modb),则 x 称为 amodb 的逆元,记作 a1
amodb 的逆元存在当且仅当 ap

费马小定理求逆元

对于p为质数,由费马小定理

ap11(modb)

axab1(modb)xab2(modb)

于是可以用快速幂求解

il int qpow(int a,int b,int p){
    ri int as=1;
    while(b>0){
        if(b&1) as=as*a%p;
        a=a*a%p,b>>=1;
    }
    return as;
} 
il int Inv(int a,int p){
    return qpow(a,p-2,p);
}

扩展欧几里得法求逆元

递归解线性同余方程 ax1(modb)即可

il void exgcd(cs int a,cs int b,int &x,int &y,int &g){
    if(!b) return x=1,y=0,g=a,void();
    return exgcd(b,a%b,y,x,g),y-=x*(a/b),void();
}
il int Inv(int a,int p){
    int x=0,y=0,g=0;
    exgcd(a,p,x,y,g);
    return (x%p+p)%p;
}

线性求1~n的逆元

x1{1,x=1px(pmodx)1,otherwise(modp)

il void solve(int n,int p){
    inv[1]=1;
    for(ri int i=2;i<=n;++i){
        inv[i]=(-p/i*inv[p%i]%p+p)%p;
    } 
    return;
}

线性求任意n个数的逆元

首先计算 n 个数的前缀积,记为 si,然后使用快速幂或扩展欧几里得法计算 sn 的逆元,记为 svn
因为 svnn 个数的积的逆元,所以当我们把它乘上 an 时,就会和 an 的逆元抵消,于是就得到了 a1an1 的积逆元,记为 svn1
同理我们可以依次计算出所有的 svi,于是 ai1 就可以用 si1×svi 求得。
所以我们就在 O(n+logp) 的时间内计算出了 n 个数的逆元。

il void solve(int n,int p){
    s[0]=1;
    for(ri int i=1;i<=n;++i){
        s[i]=s[i-1]*a[i]%p;
    } 
    sv[n]=Inv(s[i],p);
    for(ri int i=n;i;--i){
        sv[i-1]=sv[i]*a[i]%p;
    }
    for(ri int i=1;i<=n;++i){
        inv[i]=s[i-1]*sv[i]%p;
    }    
    return;
}

edit

posted @   雨夜风月  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示