乘法逆元&矩阵求逆
乘法逆元简介
模意义下乘法运算的逆元
- 定义:如果一个线性同余方程 \(ax \equiv 1 \pmod b\),则 \(x\) 称为 \(a \bmod b\) 的逆元,记作 \(a^{-1}\)。
- 分数取模:设\(c\)为\(b\)的逆元,则有\(( a/b ) \mod m = a*c \mod m\)
费马小定理法
扩展欧几里得法
定理1
线性同余方程 \(ax\equiv b \pmod n\) 可以改写为如下线性不定方程:\(ax + nk = b\)
其中 \(x\) 和 \(k\) 是未知数。
有整数解的充要条件为 \(\gcd(a,n) \mid b\)。
对于线性不定方程 \(ax+nk=b\),可以先用扩展欧几里得算法求出一组 \(x_0,k_0\),也就是 \(ax_0+nk_0=\gcd(a,n)\),然后两边同时除以 \(\gcd(a,n)\),再乘 \(b\)。就得到了方程$$
a\dfrac{b}{\gcd(a,n)}x_0+n\dfrac{b}{\gcd(a,n)}k_0=b$$于是找到方程的一个解。
定理2
若 \(\gcd(a,n)=1\),且 \(x_0、k_0\) 为方程 \(ax+nk=b\) 的一组解,则该方程的任意解可表示为:
并且对任意整数 t 都成立。
根据定理 2,可以从已求出的一个解,求出方程的所有解。实际问题中,往往要求出一个最小整数解,也就是一个特解$$x=(x \bmod t+t) \bmod t$$
其中有$$
t=\dfrac{n}{\gcd(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意义下的下的逆元
}
线性求逆元
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\) 个数的前缀积,记为 \(s_i\),然后使用快速幂或扩展欧几里得法计算 \(s_n\) 的逆元,记为 \(sv_n\)。
因为 \(sv_n\) 是 \(n\) 个数的积的逆元,所以当我们把它乘上 \(a_n\) 时,就会和 \(a_n\) 的逆元抵消,于是就得到了 \(a_1\) 到 \(a_{n-1}\) 的积逆元,记为 \(sv_{n-1}\)。
同理我们可以依次计算出所有的 \(sv_i\),于是
\(a_i^{-1}\) 就可以用 \(s_{i-1} \times sv_i\) 求得。
复杂度 \(O(n + \log p)\)。
点击查看代码
#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;
}

浙公网安备 33010602011771号