bzoj4596 [Shoi2016]黑暗前的幻想乡

题目描述:

bz

luogu

题解:

容斥+矩阵树。

考虑用其中$i$个人(没有每人一条路的限制)能组成的生成树的个数。

所以$2^{n-1}$枚举然后$n^3$高消即可。

高消常数小不虚。

代码:

#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 20;
const int MOD = 1000000007;
template<typename T>
inline void read(T&x)
{
    T f = 1,c = 0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    x = f*c;
}
template<typename T>
inline void Mod(T&x){if(x>=MOD)x-=MOD;}
int fastpow(int x,int y)
{
    int ret = 1;
    while(y)
    {
        if(y&1)ret=1ll*ret*x%MOD;
        x=1ll*x*x%MOD;y>>=1;
    }
    return ret;
}
int inv(int x){return fastpow(x,MOD-2);}
struct Pair
{
    int u,v;
    Pair(){}
    Pair(int u,int v):u(u),v(v){}
};
int n,a[N][N];
vector<Pair>ve[N];
int gs()
{
    int ret = 1;
    for(int i=1;i<n;i++)
    {
        int tmp = i;
        while(tmp<n&&!a[tmp][i])tmp++;
        if(tmp==n)return 0;
        if(tmp!=i)
        {
            ret = MOD-ret;
            for(int j=i;j<n;j++)
                swap(a[i][j],a[tmp][j]);
        }
        ret = 1ll*ret*a[i][i]%MOD;
        int now = inv(a[i][i]);
        for(int j=i;j<n;j++)
            a[i][j] = 1ll*a[i][j]*now%MOD;
        for(int j=i+1;j<n;j++)if(a[j][i])
        {
            now = a[j][i];
            for(int k = i;k<n;k++)
                Mod(a[j][k] += MOD-1ll*now*a[i][k]%MOD);
        }
    }
    return ret;
}
int main()
{
    read(n);
    for(int m,u,v,i=0;i<n-1;i++)
    {
        read(m);
        while(m--)
            read(u),read(v),ve[i].push_back(Pair(u,v));
    }
    int ans = 0;
    for(int i=0;i<(1<<(n-1));i++)
    {
        int f = (n&1?1:-1);memset(a,0,sizeof(a));
        for(int j=0;j<n-1;j++)if(i&(1<<j))
        {
            f = -f;
            for(int k=0,lim=ve[j].size();k<lim;k++)
            {
                int u = ve[j][k].u,v = ve[j][k].v;
                a[u][u]++,a[v][v]++;
                Mod(a[u][v]+=MOD-1),Mod(a[v][u]+=MOD-1);
            }
        }
        int now = gs();
        Mod(ans += (f==1?now:MOD-now));
    }
    printf("%d\n",ans);
    return 0;
}
View Code

 

posted @ 2019-07-04 15:48  LiGuanlin  阅读(134)  评论(0编辑  收藏  举报