bzoj4596: [Shoi2016]黑暗前的幻想乡

一波卡线AC美滋滋。。

这题以前看过,但是不会矩阵树定理就弃了

今天再看还是不是很会。。

状压一波,0/1表示这个公司取还是不取,那么就把这个公司能够修的边放进图弄基尔霍夫矩阵求行列式,但是这样并不能保证这个公司必定被取

考虑容斥,就要减去这个公司一定不取的情况……

假如奇偶性和n-1就加,否则就减

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib> 
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const LL mod=1e9+7;
LL MOD(LL x){return (x%mod+mod)%mod;}

int n;
LL kf[20][20];
LL gethls()
{
    LL ans=1,tp=1;
    for(int i=2;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            int x=i,y=j;
            while(kf[y][i]!=0)
            {
                LL t=kf[x][i]/kf[y][i];
                for(int k=i;k<=n;k++)
                    kf[x][k]=MOD(kf[x][k]-MOD(kf[y][k]*t));
                swap(x,y);
            }
            if(x!=i)
            {
                tp=0-tp;
                for(int k=2;k<=n;k++)
                    swap(kf[x][k],kf[y][k]);
            }
        }
        ans=MOD(ans*kf[i][i]);
    }
    ans=MOD(ans*tp);
    return ans;
}

struct repair
{
    int x,y;
}c[20][410];int clen[20];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        scanf("%d",&clen[i]);
        for(int j=1;j<=clen[i];j++)
            scanf("%d%d",&c[i][j].x,&c[i][j].y);
    }
    
    int lim=(1<<(n-1))-1;LL ans=0;
    for(int zt=0;zt<=lim;zt++)
    {
        int o=0;
        memset(kf,0,sizeof(kf));
        for(int i=1;i<=n;i++)
        {
            if( (zt& (1<<(i-1)) )>0)
            {
                o++;
                for(int j=1;j<=clen[i];j++)
                {
                    kf[c[i][j].x][c[i][j].x]++;
                    kf[c[i][j].y][c[i][j].y]++;
                    kf[c[i][j].x][c[i][j].y]--;
                    kf[c[i][j].y][c[i][j].x]--;
                }
            }
        }
        if((n-1)%2==o%2)ans=MOD(ans+gethls());
        else ans=MOD(ans-gethls());
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/AKCqhzdy/p/8933750.html