bzoj 4596

考虑容斥,容斥系数-1

首先不难发现,如果没有一个公司一条边这个限制的话,就是一个很简单的矩阵树定理了

可是有了这个限制,就会出现重复

因此我们用容斥原理来解决

我们枚举哪个(些)公司没被用到,对剩下的公司跑矩阵树定理,乘一个容斥系数累计贡献即可

时间复杂度$O(n^{3}2^{n})$

代码:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#define ll long long 
using namespace std;
const ll mode=1000000007;
ll C[25][25],D[25][25],A[25][25];
struct node
{
    int l,r;
    node (){}
    node (int a,int b):l(a),r(b){}
}V[25][505];
int num[25];
int n;
ll pow_mul(ll x,ll y)
{
    ll ret=1;
    while(y)
    {
        if(y&1)ret=ret*x%mode;
        x=x*x%mode,y>>=1;
    }
    return ret;
}
ll get_inv(ll x)
{
    return pow_mul(x,mode-2);
}
ll Gauss()
{
    int N=n-1;
    ll ans=1,f=1;
    for(int i=1;i<=N;i++)
    {
        int temp=i;
        while(!C[temp][i]&&temp<=N)temp++;
        if(temp!=i){f=-f;for(int j=i;j<=N;j++)swap(C[i][j],C[temp][j]);}
        ll inv=get_inv(C[i][i]);
        for(int j=i+1;j<=N;j++)
        {
            ll now=C[j][i];
            for(int k=i;k<=N;k++)C[j][k]=(C[j][k]-inv*now%mode*C[i][k]%mode+mode)%mode;
        }
        if(!C[i][i])return 0;
        ans=ans*C[i][i]%mode;
    }
    return (ans*f+mode)%mode;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int m;
        scanf("%d",&m);
        num[i]=m;
        for(int j=1;j<=m;j++)
        {
            int st,ed;
            scanf("%d%d",&st,&ed);
            D[st][st]++,D[ed][ed]++;
            A[st][ed]++,A[ed][st]++;
            V[i][j]=node(st,ed);
        }
    }    
    ll S=0;
    for(int i=0;i<(1<<(n-1));i++)
    {
        ll f=1;
        for(int j=0;j<n-1;j++)
        {
            if((1<<j)&i)
            {
                f=-f;
                for(int k=1;k<=num[j+1];k++)D[V[j+1][k].l][V[j+1][k].l]--,D[V[j+1][k].r][V[j+1][k].r]--,A[V[j+1][k].l][V[j+1][k].r]--,A[V[j+1][k].r][V[j+1][k].l]--;
            }
        }
        for(int j=1;j<n;j++)for(int k=1;k<n;k++)C[j][k]=(D[j][k]-A[j][k]+mode)%mode;
        S=(S+f*Gauss()+mode)%mode;
        for(int j=0;j<(n-1);j++)if((1<<j)&i)for(int k=1;k<=num[j+1];k++)D[V[j+1][k].l][V[j+1][k].l]++,D[V[j+1][k].r][V[j+1][k].r]++,A[V[j+1][k].l][V[j+1][k].r]++,A[V[j+1][k].r][V[j+1][k].l]++;
    }
    printf("%lld\n",S);
    return 0;
}

 

posted @ 2019-07-04 15:01  lleozhang  Views(175)  Comments(0Edit  收藏  举报
levels of contents