P4336 [SHOI2016]黑暗前的幻想乡

传送门

首先这题要用到矩阵树,简单来说的话就是一个无向图的生成树个数可以按如下方法计算。设图(G)的邻接矩阵为(A),度数矩阵为(D),其中邻接矩阵的第(i)行第(j)列表示(i)(j)之间有多少条边(允许重边),度数矩阵的第(i)行第(i)列表示(i)的度数且除对角线外所有元素均为(0)。那么这个无向图的基尔霍夫矩阵(K=D-A)(K)的任意一个主子式(即去掉第(i)行第(i)列后剩下的矩阵的行列式)的绝对值即为该无向图的生成树

矩阵的行列式的话……直接用高斯消元把它消成上三角矩阵,记录一下行的交换次数表示正负即可

然后本题明显要用到容斥,(ans=)刚好有(n-1)个公司的方案(-)刚好有(n-2)个公司的方案(+...)

暴力枚举即可

//minamoto
#include<bits/stdc++.h>
#define ll long long
#define rint register int
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
int read(){
    int res,f=1;char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
const int N=21,P=1e9+7;
inline int add(int x,int y){return x+y>=P?x+y-P:x+y;}
inline int dec(int x,int y){return x-y<0?x-y+P:x-y;}
inline int ksm(int a,int b){int res=1;for(;b;b>>=1,a=1ll*a*a%P)if(b&1)res=1ll*res*a%P;return res;}
int n,m,u,v,tot,ans,head[N],a[N][N],G[N][N];struct eg{int nx,u,v;}e[8005];
int det(int n){
	int ans=1,f=1,t,inv,mx;
	for(rint i=1;i<=n;++i)for(rint j=1;j<=n;++j)G[i][j]=add(a[i][j],P);
	for(rint i=1;i<=n;++i){
		mx=i;
		for(rint j=i;j<=n;++j)if(G[j][i]>G[mx][i])mx=j;
		if(mx!=i){for(rint k=i;k<=n;++k)swap(G[i][k],G[mx][k]);f=-f;}
		inv=ksm(G[i][i],P-2);
		for(rint j=i+1;j<=n;++j)if(G[j][i]){
			t=1ll*G[j][i]*inv%P;
			for(rint k=i;k<=n;++k)G[j][k]=dec(G[j][k],1ll*G[i][k]*t%P);
		}ans=1ll*ans*G[i][i]%P;
	}
	return add(P,f*ans);
}
void dfs(int x,int y){
//	printf("%d
",ans);
	if(x==n)return (void)(ans=y&1?dec(ans,det(n-1)):add(ans,det(n-1)));
    dfs(x+1,y);
	for(rint i=head[x];i;i=e[i].nx){
		u=e[i].u,v=e[i].v;
		--a[u][u],--a[v][v],++a[u][v],++a[v][u];
	}
	dfs(x+1,y+1);
	for(rint i=head[x];i;i=e[i].nx){
		u=e[i].u,v=e[i].v;
		++a[u][u],++a[v][v],--a[u][v],--a[v][u];
	}
}
inline void add_edge(int i,int u,int v){e[++tot]={head[i],u,v},head[i]=tot;}
int main(){
//	freopen("testdata.in","r",stdin);
	n=read();
	for(rint i=1;i<n;++i){
		m=read();
		for(rint j=1;j<=m;++j)u=read(),v=read(),add_edge(i,u,v),++a[u][u],++a[v][v],--a[u][v],--a[v][u];
	}
	dfs(1,0);printf("%d
",ans);return 0;
}
原文地址:https://www.cnblogs.com/bztMinamoto/p/9979476.html