description
一张无向图上有(n-1)中颜色的边,求包含每种颜色恰好一条边的生成树的个数模(10^9+7)。
(nle17)。
sol
先大力猜一波这题的复杂度是(O(2^n imes n^3))。
(2^{n-1})枚举每种颜色是否可以选,然后算出用可以选的颜色的边任意构造生成树的方案,矩阵树可以直接做。接着容斥一下就行了。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int gi(){
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
const int N = 20;
const int mod = 1e9+7;
int n,len[N],u[N][N*N],v[N][N*N],chos[N],a[N][N],ans;
int work(){
memset(a,0,sizeof(a));int res=1;
for (int i=1;i<n;++i)
if (chos[i])
for (int j=1;j<=len[i];++j)
++a[u[i][j]][u[i][j]],++a[v[i][j]][v[i][j]],--a[u[i][j]][v[i][j]],--a[v[i][j]][u[i][j]];
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
a[i][j]=(a[i][j]+mod)%mod;
for (int i=2;i<=n;++i){
for (int j=i+1;j<=n;++j)
while (a[j][i]){
int t=a[i][i]/a[j][i];
for (int k=i;k<=n;++k)
a[i][k]=(a[i][k]-1ll*t*a[j][k]%mod+mod)%mod,swap(a[i][k],a[j][k]);
res=(mod-res)%mod;
}
res=1ll*res*a[i][i]%mod;
}
return res;
}
void dfs(int u,int op){
if (u==n){
ans+=1ll*op*work()%mod;if (ans>=mod) ans-=mod;
return;
}
chos[u]=1;dfs(u+1,mod-op);
chos[u]=0;dfs(u+1,op);
}
int main(){
n=gi();
for (int i=1;i<n;++i){
len[i]=gi();
for (int j=1;j<=len[i];++j)
u[i][j]=gi(),v[i][j]=gi();
}
dfs(1,n&1?1:mod-1);
printf("%d
",ans);
return 0;
}