高斯消元
高斯消元两种形式
定义:
使用高斯消元时,我们会碰到两种形式:
正常的高斯消元,没有模数或模数为质数
设枚举了矩阵中的两行:
\[\quad
\begin{bmatrix} a_{i,i} & a_{i,i+1} & .... & a_{i,n} \\ a_{j,i} & a_{j,i+1} & .... & a_{j,n} \end{bmatrix}
\quad
\]
根据高斯消元,我们现在要把每一个 \(a_{i,k}(i \leq k \leq n)\) 乘上 \(\frac{a_{j,i}}{a_{i,i}}\)
然后再把每一个 \(a_{j,k}(i \leq k \leq n)\) 减去 \(a_{i,k}\) ,这样就能消去 \(a_{j,i}\)
简单来说,就是对 \(i \leq k \leq n\) , \(a_{j,k} \rightarrow (a_{j,k}-a_{j,k}\frac{a_{j,i}}{a_{i,i}})\)
这样的高斯消元可以用 \(double\) 直接算,模数为质数情况下也可以利用逆元处理。
代码:
for(int i=1;i<=n;i++){
int now=i;
for(int j=i+1;j<=n;j++) if(fabs(a[j][i])>fabs(a[now][i])) now=j;
//寻找 a[?][i] 最大的一行,作为辗转相除法的开始
if(now!=i) for(int j=1;j<=n;j++) swap(a[now][j],a[i][j]);
for(int j=i+1;j<=n;j++){//枚举下面行
double mul=a[j][i]/a[i][i];
for(int k=i;k<=n;k++) a[j][k]-=a[i][k]*mul;
//对于第j行的 [i,n] ,进行值的减少
}
}
模数不是质数,例如[HEOI2015]小 Z 的房间
这种情况下,我们只能用辗转相除法解决。
考虑到我们的目的是消除 \(a_{j,i}\) ,因此可以对矩阵进行两行交换,一行减去另一行的若干倍。
还是同样的矩阵,我们可以把 \(a_{i,k}\) 减去 \(a_{j,k}\lfloor\frac{a_{i,i}}{a_{j,i}}\rfloor(i \leq k \leq n)\) ,然后再交换第 \(i\) 和第 \(j\) 行。
辗转相除到最后,肯定有 \(a_{j,i}=0\) 。
具体解释可以看这道例题的第一篇题解,对辗转相除法作了比较好的解释。
代码:
for(int i=1;i<cnt;i++){
for(int j=i+1;j<=cnt;j++){//枚举矩阵每一行
while(a[j][i]){//达成目的
int mul=a[i][i]/a[j][i];
for(int k=i;k<=cnt;k++) a[i][k]=(a[i][k]-mul*a[j][k]%mod+mod)%mod;
swap(a[i],a[j]);//上下交换
ans*=-1;//交换矩阵两行换符号
}
}
}
辗转相除法的时间复杂度过大,尽量不用,除非模数是非质数
不关注的有难了😠😠😠https://b23.tv/hoXKV9