【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;
}

 

posted @ 2017-09-27 19:50  Illya  阅读(179)  评论(1编辑  收藏  举报