SHOI2016 黑暗前的幻想乡

题目链接:戳我

幻想乡是个什么东西??(逃

矩阵树定理+容斥

就是设\(dp[i]\)表示至多i个公司修建道路,那么我们有\(ans=dp[n-1]-dp[n-2]+dp[n-3]......\)balabala(就是那个容斥公式嘛qwqwq)

然后每次都跑一次矩阵树定理qwqwq

但是这样的时间复杂度是\(O(n^32^{n-1})\)???所以说。。。跑的。。。2s。。。很勉强qwqwq

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define MAXN 100010
#define mod 1000000007
using namespace std;
int n,maxx,ans;
int cnt[MAXN],dp[20][20];
struct Node{int x,y;};
vector<Node>node[20];
inline int getnum(int x)
{
    int cur_ans=0;
    for(int i=0;i<=21;i++)
        if(x&(1<<i))
            cur_ans++;
    return cur_ans;
}
inline int matrix_tree()
{
    int cur_ans=1;
    for(int i=2;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            while(dp[j][i])
            {
                int t=dp[i][i]/dp[j][i];
                for(int k=i;k<=n;k++)
                    dp[i][k]=(dp[i][k]-1ll*dp[j][k]*t%mod+mod)%mod;
                swap(dp[i],dp[j]);
                cur_ans=(-cur_ans+mod)%mod;
            }
        }
        cur_ans=(1ll*cur_ans*dp[i][i])%mod;
    }
    return cur_ans;
}
inline int calc(int x)
{
    memset(dp,0,sizeof(dp));
    for(int i=1;i<n;i++)
    {
        if(x&(1<<(i-1)))
        {
            for(int j=0;j<node[i].size();j++)
            {
                int u=node[i][j].x,v=node[i][j].y;
                dp[u][u]=(dp[u][u]+1)%mod;
                dp[v][v]=(dp[v][v]+1)%mod;
                dp[u][v]=(dp[u][v]-1+mod)%mod;
                dp[v][u]=(dp[v][u]-1+mod)%mod;
            }
        }
    }
    return matrix_tree();
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    freopen("ce.out","w",stdout);
    #endif
    scanf("%d",&n);
    maxx=(1<<n-1)-1;
    for(int i=1;i<n;i++)
    {
        int k,u,v;
        scanf("%d",&k);
        for(int j=1;j<=k;j++)
        {
            scanf("%d%d",&u,&v);
            node[i].push_back((Node){u,v});
        }
    }
    for(int i=0;i<=maxx;i++) cnt[i]=getnum(i);
    for(int i=0;i<1<<(n-1);++i) 
        ans=(ans+(((n-1-cnt[i])&1)?mod-calc(i):calc(i)))%mod;
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/fengxunling/p/10429756.html