乘法逆元&矩阵求逆

乘法逆元简介

模意义下乘法运算的逆元

  • 定义:如果一个线性同余方程 ax1(modb),则 x 称为 amodb 的逆元,记作 a1
  • 分数取模:设cb的逆元,则有(a/b)modm=acmodm

费马小定理

ax1(modb)axab1(modb)xab2(modb)

扩展欧几里得

OI-wiki

定理1

线性同余方程 axb(modn) 可以改写为如下线性不定方程:ax+nk=b
其中 xk 是未知数。
有整数解的充要条件为 gcd(a,n)b
对于线性不定方程 ax+nk=b,可以先用扩展欧几里得算法求出一组 x0,k0,也就是 ax0+nk0=gcd(a,n),然后两边同时除以 gcd(a,n),再乘 b。就得到了方程abgcd(a,n)x0+nbgcd(a,n)k0=b于是找到方程的一个解。

定理2

gcd(a,n)=1,且 x0k0 为方程 ax+nk=b 的一组解,则该方程的任意解可表示为:

x=x0+ntk=k0at

并且对任意整数 t 都成立。
根据定理 2,可以从已求出的一个解,求出方程的所有解。实际问题中,往往要求出一个最小整数解,也就是一个特解x=(xmodt+t)modt
其中有t=ngcd(a,n)

void exgcd(cs int a,cs int b,int &x,int &y)
{
    if (!b) return x=1,y=0,void();
    exgcd(b,a%b,y,x), y-=a/b*x;
}
int main()
{
    int x,y; exgcd(a,Mod,x,y);
    x=(x%Mod+Mod)%Mod,wt(x); //x是 a 在 mod p意义下的下的逆元
}

线性求逆元

i1{1,if i=1,pi1(pmodi)1,otherwise.(modp)

P3811 【模板】乘法逆元

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

线性求任意 n 个数的逆元

首先计算 n 个数的前缀积,记为 si,然后使用快速幂或扩展欧几里得法计算 sn 的逆元,记为 svn

因为 svnn 个数的积的逆元,所以当我们把它乘上 an 时,就会和 an 的逆元抵消,于是就得到了 a1an1 的积逆元,记为 svn1

同理我们可以依次计算出所有的 svi,于是
ai1 就可以用 si1×svi 求得。

复杂度 O(n+logp)

P5431 【模板】乘法逆元 2

点击查看代码
#include<bits/stdc++.h>
#define cs const
#define il inline
#define ri register
#define pc(i) putchar(i)
#define int long long
using namespace std;
il void read(int &as)
{
	as=0;int f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') as=(as<<3)+(as<<1)+(ch^48),ch=getchar();as*=f;
}
void wt(int x){if(x<0) x=-x,pc('-');if(x>9) wt(x/10);pc(x%10|48);}
cs int N=5e6+7;
int n,Mod,k,a[N],s[N],sv[N],ans,kk;
il int qpow(int base,int power)
{
	int re=1;
	while(power>0)
	{
		if(power&1) (re*=base)%=Mod;
		power>>=1,(base*=base)%=Mod;		
	}
	return re;
}
signed main()
{
	s[0]=1,read(n),read(Mod),read(k),kk=k;
	for(ri int i=1;i<=n;++i) 
		read(a[i]),s[i]=s[i-1]*a[i]%Mod;
	sv[n]=qpow(s[n],Mod-2);
	for(ri int i=n;i>=1;--i) 
		sv[i-1]=sv[i]*a[i]%Mod;
	for(ri int i=1;i<=n;++i)
		(ans+=kk*s[i-1]%Mod*sv[i]%Mod)%=Mod,(kk*=k)%=Mod;
	wt(ans); 
	return 0;
}

矩阵求逆

高斯消元,分数取模用上述方法转化即可

点击查看代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#define il inline
#define ri register
#define pc(i) putchar(i)
#define int long long
using namespace std;
const int Mod=1e9+7,N=500;
int n,a[N][N<<1];
il void wt(int x){if(x<0)pc('-'),x=-x;if(x>9)wt(x/10);pc(x%10+48);}
il int qpow(int b,int p){int re=1;while(p>0){if(p&1)re=re*b%Mod;p>>=1,b=b*b%Mod;}return re%Mod;} 
il void Pt(){for(ri int i=1;i<=n;++i){for(ri int j=n+1;j<=n+n;++j)printf("%lld ",a[i][j]);pc('\n');}}
il int inv(int x){return qpow(x,Mod-2)%Mod;}
il int M(int x) {return (x%Mod+Mod)%Mod;}
il void Gauss()
{
    for(ri int i=1;i<=n;++i)
    {
        int Max=i,ai;
        for(ri int j=i+1;j<=n;++j) if(abs(a[Max][i])<abs(a[j][i])) Max=j;//upd: >
        if(!a[Max][i]) return puts("No Solution"),void();
        swap(a[Max],a[i]),ai=inv(a[i][i]); 
        for(ri int j=1;j<=n;++j)
        {
            if(j==i) continue;
            int p=a[j][i]*ai%Mod;// a[j][i]/a[i][i]%Mod
            for(ri int k=1;k<=n+n;++k) a[j][k]=M(a[j][k]-p*a[i][k]);
        }
        for(ri int k=1;k<=n+n;++k) a[i][k]=a[i][k]*ai%Mod; // a[i][k]/a[i][i]%Mod
    }
    Pt();
}
signed main()
{
    scanf("%lld",&n);
    for(ri int i=1;i<=n;++i)
    for(ri int j=1;j<=n;++j)scanf("%lld",&a[i][j]),a[i][i+n]=1;
    Gauss();
    return 0;
}
posted @   Bertidurlah  阅读(106)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示