行列式


行列式

題目大意

​ 給定一個無向聯通圖,求其鄰接矩陣行列式。

\(n\leq 3\times 10^4 , m\leq 3\times 10^5\) ,保證每個邊雙聯通分量點數 \(\leq 50\)

題解

​ 考慮這個鄰接矩陣的行列式的意義,在不考慮行列式中的 \(-1\) 系數的情況下,就是選出若干個存在的有向環,不重不漏地覆蓋每個點的方案數。

​ 我們發現一個排列中環與環之間產生的逆序對數是可以忽略的,因此如果每個環都在一個邊雙內部,答案就是每個邊雙的答案的乘積。

​ 考慮一個橋出現在了環中,那么一定是橋的兩個端點組成了二元環。

​ 考慮建出邊雙樹, \(F_{x,0/1}\) 表示 \(x\) 號邊雙,其與邊雙樹父親連接的那個點有沒有被環覆蓋的方案數。
​ 若 \(x\) 中一個點 \(u\)\(x\) 的某個兒子 \(y\) 中的一個點 \(v\) 組成了二元環,那么我們可視為在 \(x\) 內部的鄰接矩陣中,\(u\) 自己添加了一個自環,其權值自帶 \(-1\) 的系數,然后求行列式即可算出 \(F_{x,1}\)

同樣,我們將 \(x\)\(x\) 父親連接的點 \(w\) 在鄰接矩陣的邊都扣摳掉,並加上一個自環即可等價算出 \(F_{x,0}\)

#include<bits/stdc++.h>
#define debug(x) cerr<<#x<<" = "<<x
#define sp <<"  "
#define el <<endl
#define fgx cerr<<"-----------------------------------"<<endl
#define LL long long
#define uint unsigned int
#define ULL unsigned long long
#define LDB long double 
#define DB double
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
using namespace std;
inline int read(){
	int nm=0; bool fh=true; char cw=getchar();
	for(;!isdigit(cw);cw=getchar()) fh^=(cw=='-');
	for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
	return fh?nm:-nm;
}
#define mod 998244353
namespace CALC{
	inline int add(int x,int y){return (x+y>=mod)?(x+y-mod):(x+y);}
	inline int mns(int x,int y){return (x-y<0)?(x-y+mod):(x-y);}
	inline int mul(int x,int y){return (LL)x*(LL)y%mod;}
	inline void upd(int &x,int y){x=((x+y>=mod)?(x+y-mod):(x+y));}
	inline void dec(int &x,int y){x=((x-y<0)?(x-y+mod):(x-y));}
	inline int qpow(int x,int sq){int res=1;for(;sq;sq>>=1,x=mul(x,x))if(sq&1)res=mul(res,x);return res;}
}using namespace CALC;
#define M 30020
int n,m,t[53][53],p[53][53];
inline int calc(int K,int ans=1){
	if(!K) return 1; memcpy(p,t,sizeof(p));
	for(int k=1,i=1;i<=K;i++){
		for(k=i;k<=K&&!p[k][i];++k); if(k>K) return 0;
		if(k^i){for(int j=i;j<=K;j++) swap(p[k][j],p[i][j]);ans=mul(ans,mod-1);}
		int bas=p[i][i]; ans=mul(ans,bas),bas=qpow(bas,mod-2);
		for(int j=i;j<=K;j++) p[i][j]=mul(p[i][j],bas);
		for(int w=i+1;w<=K;w++) if(p[w][i]){
			int tmp=p[w][i];
			for(int j=i;j<=K;j++) dec(p[w][j],mul(tmp,p[i][j]));
		}
	} return ans;
}
int fs[M],nt[M*20],to[M*20],u[M*10],v[M*10],tmp,id[M];
inline void link(int x,int y){nt[tmp]=fs[x],fs[x]=tmp,to[tmp++]=y;}
int dfn[M],low[M],cnt,be[M],F[M][2],anc[M],tot,G[M],S[M],top;
vector<int>nd[M],eg[M],son[M];
inline void init(int x,int last){
	dfn[x]=++cnt,low[x]=cnt,S[++top]=x;
	for(int i=fs[x];i!=-1;i=nt[i]) if(to[i]^last){
		if(!dfn[to[i]]) init(to[i],x);
		low[x]=min(low[x],low[to[i]]);
	} if(low[x]<dfn[x]) return; ++tot;
	while(!be[x]) be[S[top]]=tot,nd[tot].pb(S[top]),top--;
	if(last) son[last].pb(x); anc[tot]=x;
}
inline void DP(int w){
	for(int i=0,TP=nd[w].size();i<TP;i++)
		for(int x=nd[w][i],j=0,SZ=son[x].size();j<SZ;++j) DP(be[son[x][j]]);
	int K=nd[w].size(); memset(t,0,sizeof(t)); sort(nd[w].begin(),nd[w].end());
	for(int j=0;j<K;j++){
		int y,x=nd[w][j],g1=0,g0=1; id[x]=j+1;
		for(int i=0,TP=son[x].size();i<TP;++i){
			y=be[son[x][i]],g1=mul(g1,F[y][1]);
			dec(g1,mul(g0,F[y][0])),g0=mul(g0,F[y][1]);
		} t[j+1][j+1]=g1,G[j+1]=g0;
	}
	for(int i=0,TP=eg[w].size();i<TP;i++){	
		int x=id[eg[w][i]/M],y=id[eg[w][i]%M];
		t[x][y]=G[x],t[y][x]=G[y];
	} F[w][1]=calc(K); int ps=id[anc[w]];
	for(int i=1;i<=K;i++) t[i][ps]=t[ps][i]=0;
	for(int i=1;i<K;i++) for(int j=1;j<K;j++){
		if(i<ps&&j<ps) continue;
		if(i<ps) t[i][j]=t[i][j+1];
		else if(j<ps) t[i][j]=t[i+1][j];
		else t[i][j]=t[i+1][j+1];
	} F[w][0]=calc(K-1);
	for(int x=anc[w],i=0,TP=son[x].size();i<TP;++i)
		F[w][0]=mul(F[w][0],F[be[son[x][i]]][1]);
}
int main(){
	n=read(),m=read(),read(),memset(fs,-1,sizeof(fs));
	for(int i=1,x,y;i<=m;i++) x=read(),y=read(),u[i]=x,v[i]=y,link(x,y),link(y,x); init(1,0);
	for(int i=1;i<=m;i++) if(be[u[i]]==be[v[i]]) eg[be[u[i]]].pb(u[i]*M+v[i]); DP(tot);
	printf("%d\n",F[tot][1]); return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM