[BZOJ4596][SHOI2016]黑暗前的幻想乡

bzoj
luogu

description

一张无向图上有\(n-1\)中颜色的边,求包含每种颜色恰好一条边的生成树的个数模\(10^9+7\)
\(n\le17\)

sol

先大力猜一波这题的复杂度是\(O(2^n\times 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\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zhoushuyu/p/9245572.html