黑暗前的幻想乡[SHOI2016][容斥原理][矩阵树定理]

文章目录

题目

Luogu
n n 个点,修成一棵树, n 1 n-1 个公司,每个公司能修一些边,但只能修一条,求方案数

思路

由于是树,所以条件转化(最重要的一步):
[每个公司修一条边]=[每个公司修边]=[ a 1 a_1 \cap a 2 a_2 \cap \cap a n a_n 修]
于是 2 n 2^n 枚举公司然后矩阵树即可
时间复杂度 O ( 2 n n 3 ) O(2^n*n^3)

另解

自己瞎想的
矩阵树每个点看成一个 2 n 1 2^{n-1} 项的多项式,每一项为 k a t 1 a t 2 . . . a t m k*a_{t_1}a_{t_2}...a_{t_m}
开始时形如 a t 1 a t 2 . . . -a_{t_1}-a_{t_2}-... 或者 a t 1 + a t 2 . . . a_{t_1}+a_{t_2}... 之类的
好像不能消元…咕了
O ( 2 n n 3 ) O(2^n*n^3)

代码

//#pragma GCC optimize(2)
#include<set>    
#include<map>    
#include<stack>    
#include<ctime>    
#include<cstdio>    
#include<queue>    
#include<cmath>    
#include<vector>    
#include<cstring>   
#include<climits>    
#include<iostream>   
#include<algorithm>
using namespace std;
#define LL long long
#define ULL unsigned long long
int read(){
    int f=1,x=0;char c=getchar();
    while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
    while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
    return f*x;
}
#define MAXN 300
#define INF 0x3f3f3f3f
#define Mod (int)(1e9+7)
LL mat[MAXN+5][MAXN+5],a[MAXN+5][MAXN+5];
LL Pow(LL x,int y){
	LL ret=1;
	while(y){
		if(y&1) ret=ret*x%Mod;
		x=x*x%Mod,y>>=1;
	}
	return ret;
}
int Det(int n){
	n--;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			mat[i][j]=(a[i][j]+Mod)%Mod;
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++)
			if(!mat[i][i]&&mat[j][i]){
				swap(mat[i],mat[j]);
				break;
			}
		LL Inv=Pow(mat[i][i],Mod-2);
		for(int j=i+1;j<=n;j++){
			LL tmp=mat[j][i]*Inv%Mod;
			for(int k=i;k<=n;k++)
				mat[j][k]=(mat[j][k]-tmp*mat[i][k]%Mod+Mod)%Mod;
		}
	}
	LL ret=1;
	for(int i=1;i<=n;i++)
		ret=ret*mat[i][i]%Mod;
	return ret;
}
int n;
LL ans;
vector<pair<int,int> > Edge[MAXN+5];
void DFS(int d,int k){
	if(d==n){
		ans=(ans+Mod+k*Det(n))%Mod;
		return ;
	}
	DFS(d+1,-k);
	for(int i=0;i<(int)Edge[d].size();i++){
		int u=Edge[d][i].first,v=Edge[d][i].second;
		a[u][u]++,a[v][v]++,a[u][v]--,a[v][u]--;
	}
	DFS(d+1,k);
	for(int i=0;i<(int)Edge[d].size();i++){
		int u=Edge[d][i].first,v=Edge[d][i].second;
		a[u][u]--,a[v][v]--,a[u][v]++,a[v][u]++;
	}
	return ;
}
int main(){
	n=read();
	for(int i=1;i<n;i++){
		int m=read();
		for(int j=1;j<=m;j++)
			Edge[i].push_back(make_pair(read(),read()));
	}
	DFS(1,1);
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37555704/article/details/107086030
今日推荐