行列式:

参考
oi-wiki

定义

对于一个\(n*n\)的矩阵A行列式取值(标量)
\(det(A)=|A|=\sum\limits_p(-1)^{\tau(p)}\prod\limits_{i=1}^na_{i,p_i}\)
\(\tau(p)\)即排列\(p\)的逆序对个数。

性质

证明后面再补

1.\(|A|=|A^T|\),即排列是按排列p下表为行的行列式等同于排列p下标为列的得到的行列式。
2.交换两行(列),行列式取相反数
3.把一个矩阵的一行(列)的值全部乘一个常数加到另一行(列)上,行列式值不变。

求解

看看性质3,是不是很像高斯消元。
然后高斯消元后面得到的是一个倒三角矩阵。(除了这个斜下对角线排列,其它排列都含零)
画画图可以发现,最后答案是\(\prod\limits_{i=1}^na_{i,i}\)。中途注意维护一下交换两行带来的正负的变化。
ps.下面这道题消元用的是辗转相减(除),因为p不一定是质数,不一定能求逆元。
code【模板】行列式求值:

#include<bits/stdc++.h>
using namespace std;
const int N=605;
int n,p,a[N][N];
void Gauss() {
	int opt=1;
	for(int i=1;i<=n;i++) {
		for(int j=i+1;j<=n;j++) {
			while(a[i][i]) {
				int d=a[j][i]/a[i][i];
				for(int k=1;k<=n;k++) {a[j][k]-=1ll*a[i][k]*d%p;a[j][k]%=p;}
				opt=-opt;swap(a[i],a[j]);
			}
			opt=-opt;swap(a[i],a[j]);
		}
	}
	int ans=opt;
	for(int i=1;i<=n;i++)ans=1ll*ans*a[i][i]%p;
	printf("%d",(ans+p)%p);
}
int main() {
	scanf("%d%d",&n,&p);
	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) {scanf("%d",&a[i][j]);}
	Gauss();
	return 0;
}

矩阵树定理

求解的是一个图中的所有生成树边权积的和

  • 无向图
    定义Laplace矩阵L为:
    \(L(G)=D(G)-A(G)\)
    其中\(D(G)\)为度数矩阵。每个\(D_{i,i}=deg[i]\)其余行列不等的值为\(0\)\(A(G)\)为邻接矩阵。
    \(L(G)\)的所有余子柿相等。
    \(|L(G)去掉一行一列|\)即为答案。
    ps.自环不计入
  • 有向图
    出树(从根往外连):\(D\)\(in[]\)入度
    入树(从外往根连):\(D\)\(out[]\)出度
    钦定根\(k\),则去掉\(k\)行,\(k\)列。
    特别的:生成树的个数\(t(G)\)即把边权赋为1,这样每个生成树的权值就是1。
  • code【模板】Matrix-Tree 定理:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=305;
const int mod=1e9+7;
ll a[N][N],mul,opt=1;
int n,m,t;
ll ksm(ll a,ll b) {ll res=1;for(;b;b>>=1,a=a*a%mod)if(b&1)res=res*a%mod;return res;}
void Gauss() {
	opt=1;
	for(int i=2;i<n;i++) {
		int r=i;
		while(r<=n&&!a[r][i]) r++;
		if(r>n) {continue;}
		if(r!=i) {swap(a[r],a[i]);opt=-opt;}
		for(int j=i+1;j<=n;j++) {
			ll d=a[j][i]*ksm(a[i][i],mod-2)%mod;
			for(int k=2;k<=n;k++) a[j][k]-=a[i][k]*d,a[j][k]%=mod;
		}
	}
	mul=opt;
	for(int i=2;i<=n;i++)mul=mul*a[i][i]%mod;
	mul=(mul+mod)%mod;
	printf("%lld\n",mul);
}
int main() {
//	freopen("data.in","r",stdin);
	scanf("%d%d%d",&n,&m,&t);
	for(int i=1;i<=m;i++) {
		int u,v,w;scanf("%d%d%d",&u,&v,&w);
		a[u][v]=(a[u][v]-w)%mod;a[v][v]=(a[v][v]+w)%mod;
		if(!t) {a[v][u]=(a[v][u]-w)%mod;a[u][u]=(a[u][u]+w)%mod;}
	}
	Gauss();
	return 0;
}

BEST 定理

\(G\)是有向欧拉图,求欧拉回路个数
\(ec(G)=t_{out(G)}*\prod\limits_{v \in V}(deg[v]-1)!\)
ps.欧拉图即含欧拉回路的图,满足\(in[v]=out[v]\),而且选哪个根都一样。