【bzoj4596】黑暗前的幻想乡
把每个公司能连的边都看做独立的边,即在所有能连的边里随便连,矩阵树。
显然有不合法的情况,每个公司只能连一条边,考虑容斥:
ans=sigma随便连-sigma一个公司不连+sigma两个公司不连-sigma三个公司不连……
容斥写错了safufu地调了半天消元QAQ
#include<bits/stdc++.h> #define maxn 20 #define MOD 1000000007 #define ll long long using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int a[maxn][maxn],D[maxn][maxn],A[maxn][maxn]; int gauss(int n){ int ret=1; for(int i=1;i<=n;++i){ for(int j=i+1;j<=n;++j){ int A=a[i][i],B=a[j][i]; while(B){ int t=A/B;A%=B;swap(A,B); for(int k=i;k<=n;++k)a[i][k]=(a[i][k]-1ll*t*a[j][k]%MOD)%MOD; for(int k=i;k<=n;++k)swap(a[i][k],a[j][k]); ret=-ret; } } if(!a[i][i])return 0; ret=1ll*ret*a[i][i]%MOD; } return (ret+MOD)%MOD; } int n,s[maxn],num[maxn],u[maxn][maxn*maxn],v[maxn][maxn*maxn]; void build(){ memset(D,0,sizeof(D)); memset(A,0,sizeof(A)); for(int i=1;i<n;++i)if(s[i]){ for(int j=1;j<=num[i];++j){ int f1=u[i][j],f2=v[i][j]; ++D[f1][f1];++D[f2][f2]; ++A[f1][f2];++A[f2][f1]; } } for(int i=1;i<n;++i) for(int j=1;j<n;++j) a[i][j]=D[i][j]-A[i][j]; } int ans; void dfs(int p,int f){ if(p>=n){ f=n-1-f; if(f&1)f=-1;else f=1; build();int gs=gauss(n-1); ans=(ans+f*gs)%MOD; return; } s[p]=1; dfs(p+1,f+1); s[p]=0; dfs(p+1,f); } int main(){ n=read(); for(int i=1;i<n;++i){ num[i]=read(); for(int j=1;j<=num[i];++j){ u[i][j]=read();v[i][j]=read(); } } dfs(1,0); printf("%d\n",(ans%MOD+MOD)%MOD); return 0; }