原理简述
大概就是模拟手工消元吧
用法
大概还是推了公式然后消元吧,其中比较特别的有matrixTree定理还有线性基。
行列式求法
对于一个矩阵进行高斯消元
最终案为(-1)^S*(主对角线之积),其中S位行与行之间交换的次数
matrixTree定理
用于一张图的生成树计数问题
理论基于基尔霍夫(Kirchhoff)矩阵,但是这里不去证明了: 介绍两个矩阵:
- 度数矩阵D:c[i][i]表示i的度数,其他的都是0
- 邻接矩阵A:就是常规意义上的0/1邻接矩阵,c[i][i]=0
那么基尔霍夫矩阵就是D-A
生成树的答案就是他的n-1阶主子式的行列式的绝对值,所谓n-1阶主子式,就是去掉第r行r列之后的新矩阵 我相信正常人都会让r=n
辗转相除法处理mod问题
我们最终目的就是为了消元,但是在有mod又没有逆元的时候,我们就要换一种方式
按照辗转相除的思想,我们最终可以让一项为0
具体操作步骤就是t=a[i][j]/a[i+1][j],然后所有元素都减去下一排*t,然后交换两排元素(保证当前排最大),继续重复操作 注意这种方法用在行列式上,辗转相除带来的交换也算是交换。
由于mod没有负数,所以必须维护符号位,如果是负数,那么答案就是mod-ans
这个东西,不能用整数LCM的做法,因为对序列乘或除一个数会使得行列式的答案改变,而且很容易爆,所以说,整数高斯消元这玩意儿,基本没用
因此要么辗转相除,要么用逆元(mod素数的时候)
一个技巧:线性方程组
在保证答案是整数以及答案很小的时候,可以把所有的除法部分换成逆元,mod大素数,避免精度误差,同时避免答案为mod倍数的情况。
代码
时间复杂度基本上是O(n^3)
辗转相除可能多个log,但实际效果很好
double类型
const int maxn=505;
const double eps=1e-8;
double A[maxn<<1][maxn],x[maxn];//A矩阵中每一行1~n存系数,n+1为答案,m个方程m行,x是最终的答案
//注意空间要多开几个,还要考虑n,m不同的情况
int n,m;
int Guass(int n,int m)//有n个未知数,m个方程
{
int i=1,j=1,k,r,c;
while(i<=m && j<