hdu 7253
显然的 \(\mathcal{O}(n^4)\) 做法是,Laplace 矩阵 \(L=D^{in}(G)-A(G)\)。由矩阵树定理可以知道 \(t^{leaf}(G,k)=\det M_{i,i}\)。根据 \(L\) 的生成方式可以知道,\(\sum_{i=1}^n L_{i,j}=0,\forall j\)。
下面介绍一点点线性代数。
一个 \(n\times m\) 的矩阵的秩 \(rank\le \min(n,m)\),并且行秩等于列秩。
如果 \(n\times n\) 的矩阵 \(D\) 的 \(rank\):
- \(=n\),则 \(\det D\neq 0\)。
- \(=n-1\),则存在一个 \((n-1)\times (n-1)\) 的余子式 \(\det\neq 0\)。
- \(<n-1\),则所有\((n-1)\times (n-1)\) 的余子式 \(\det= 0\)。
\(rank(D)\) 也等于 \(D\) 中最大线性无关向量个数。如果一组向量 \((\alpha_1,\alpha_2,\cdots,\alpha_k)\) 线性相关,当且仅当存在 $ (x_1,x_2,\cdots,x_k)\neq (0,0,\cdots ,0)$ 使得 \(\sum x_i\alpha_i=(0,0,\cdots ,0)\)。
\(M_{i,j}\) 为矩阵 \(a\) 中 \(a_{i,j}\) 的余子式,也就是 \(A\) 去掉第 \(i\) 行第 \(j\) 列的 \(n-1\) 阶矩阵的行列式。
\(A_{i,j}\) 为矩阵 \(a\) 中 \(a_{i,j}\) 的代数余子式,\(A_{i,j}=(-1)^{i+j}M_{i,j}\)。
矩阵 \(a\) 的伴随矩阵
其实,伴随矩阵对于这个题的作用不是很大,而是可以启发思考。
伴随矩阵每一列相等等价于,删除每一行是等价的,除了一个 \((-1)^{i+j}\) 的系数(看定义)。
因为 \(\sum_{i=1}^n L_{i,j}=0,\forall j\),所以 \(rank(L)\neq n\)。
如果 \(rank(L)<n-1\),输出 \(n\) 个 \(0\) 即可。
以下 \(rank(L)=n-1\)。尝试证明:\(A^*\) 中每一列相同。不妨只证明 \(A_{1,1}=A_{2,1}\),其他的有类似的证明。
命题:\(A_{1,1}=A_{2,1}\),且 \(\sum_{i=1}^n a_{i,j}=0,\forall j=1,2,\cdots, n\)。
行列式加法,
即证。
因此删掉每一行都是等价的(除了一个 \(-1\) 的系数)。
思路到这儿就结束了。注意 \(A\) 到 \(M\) 是有一个系数的。
现在开始研究写法:
我每一次删掉不同的列,还是要做一个 \(\mathcal{O}(n^3)\) 的行列式啊?
发现将 \(L\) 最后一行删掉的 \((n-1)\times n\) 矩阵做高斯消元以后,再删掉列求行列式是没有影响的(记录一个交换次数即可)。这个是因为高斯消元中我们没有做列交换,因此删掉一个列以后再做高斯消元是等价的(一个列只能影响这一个列)。
因此先做一个高斯消元,再删掉一列。现在得到的 \((n-1)\times (n-1)\) 的矩阵恰好是上海森堡矩阵。这个求行列式可以 \(\mathcal{O}(n^2)\) 求。好像有多种做法,但是简单的就是,发现一列最多只有两个位置(还是相邻的)有值,套高斯消元的外壳即可。当然也有一个展开行列式定义的 dp 做法,这里不再赘述。
因此我们 \(\mathcal{O}(n^3)\) 的完成了这个题。有可能写的时候会写到逆元,不过多一个 \(\log\) 也可以过。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 5e2+2;
const ll mod = 1e9+7;
ll pw(ll x,ll y){
ll res=1;
while (y){
if (y&1){
res=res*x%mod;
}
x=x*x%mod;
y>>=1;
}
return res;
}
ll inv(ll x){
return pw(x,mod-2);
}
struct mat {
int n,m,rank,swp;
ll a[N][N];
void init(int _n,int _m){
n=_n,m=_m;
memset(a,0,sizeof a);
rank=0;
}
void guass(){
for (int i=1; i<=n; i++){
int p=i;
for (int j=i+1; j<=m; j++){
if (a[p][i]<a[j][i]){
p=j;
}
}
for (int j=1; j<=m; j++){
swap(a[p][j],a[i][j]);
}
if (p!=i) swp++;
for (int j=1; j<=n; j++){
if (i!=j){
ll d=a[j][i]*inv(a[i][i])%mod;
for (int k=i; k<=m; k++){
a[j][k]-=a[i][k]*d%mod;
a[j][k]=(a[j][k]+mod)%mod;
}
}
}
}
for (int i=1; i<=n; i++){
if (a[i][i]) rank++;
}
}
mat delj(int x){
mat c;
c.init(n,m-1);
for (int i=1; i<=n; i++){
for (int j=1; j<=m; j++){
if (j<x) c.a[i][j]=a[i][j];
else if (j!=x) c.a[i][j-1]=a[i][j];
}
}
return c;
}
ll det(){
// Hessenberg
ll ans=1;
for (int i=1; i+1<=n; i++){
if (a[i+1][i]==0) continue;
if (a[i][i]==0){
swap(a[i],a[i+1]);
ans*=-1;
}
ll d=a[i+1][i]*inv(a[i][i])%mod;
for (int j=i; j<=n; j++){
a[i+1][j]=(a[i+1][j]-d*a[i][j]%mod)%mod;
}
}
if (swp&1) ans*=-1;
for (int i=1; i<=n; i++) ans=ans*a[i][i]%mod;
return (ans+mod)%mod;
}
} lap,lar,d;
int n,m;
void solve(){
cin>>n>>m;
lap.init(n,n);
for (int i=1; i<=m; i++){
int u,v;
cin>>u>>v;
lap.a[v][v]++;
lap.a[u][v]--;
}
lar=lap;
lap.guass();
if (lap.rank<n-1){
for (int i=0; i<n; i++){
cout<<0<<" ";
}
cout<<"\n";
return;
}
// rank=n-1
lar.swp=0;
lar.n--;
lar.guass();
for (int i=1; i<=n; i++){
d=lar.delj(i);
d.swp=lar.swp;
int ans=d.det();
cout<<((i+n)%2?(mod-ans)%mod:ans)<<" ";
}
cout<<"\n";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while (t--){
solve();
}
return 0;
}
浙公网安备 33010602011771号