【Shoi2016】黑暗前的幻想乡

时间限制 : 2000 MS 空间限制 : 256 MB

问题描述

四年一度的幻想乡大选开始了,最近幻想乡最大的问题是很多来历不明的妖怪涌入了幻想乡,扰乱了幻想乡昔日的秩序。但是幻想乡的建制派妖怪(人类)博丽灵梦和八云紫等人整日高谈所有妖怪平等,幻想乡多元化等等,对于幻想乡目前面临的种种大问题却给不出合理的解决方案。
风见幽香是幻想乡里少有的意识到了问题严重性的大妖怪。她这次勇敢地站了出来参加幻想乡大选,提出包括在幻想乡边境建墙(并让人类出钱),大力开展基础设施建设挽回失业率等一系列方案,成为了大选年出人意料的黑马并顺利地当上了幻想乡的大统领。
幽香上台以后,第一项措施就是要修建幻想乡的公路。幻想乡一共有 n 个城市,之前原来没有任何路。幽香向选民承诺要减税,所以她打算只修n−1条公路将这些城市连接起来。但是幻想乡有正好n−1个建筑公司,每个建筑公司都想在修路地过程中获得一些好处。虽然这些建筑公司在选举前没有给幽香钱,幽香还是打算和他们搞好关系,因为她还指望他们帮她建墙。所以她打算让每个建筑公司都负责一条路来修。
每个建筑公司都告诉了幽香自己有能力负责修建的路是哪些城市之间的。所以幽香打算 n−1条能够连接幻想乡所有城市的边,然后每条边都交给一个能够负责该边的建筑公司修建,并且每个建筑公司都恰好修建一条边。
幽香现在想要知道一共有多少种可能的方案呢?两个方案不同当且仅当它们要么修的边的集合不同,要么边的分配方式不同。

输入格式

第一行包含一个整数 n,表示城市个数。 接下来 n−1行,第 i 行表示 第 i 个建筑公司可以修建的路的列表:以一个非负数mi开头,表示其可以修建 mi条路;接下来有 mi对数,每对数表示一条边的两个端点。其中不会出现重复的边,也不会出现自环。

输出格式

输出一行一个整数,表示所有可能的方案数对 10^9+7 取模的结果。

样例输入

4
2 3 2 4 2
5 2 1 3 1 3 2 4 1 4 3
4 2 1 3 2 4 1 4 2

样例输出

17

提示

n<=17

题解

矩阵树定理可以解决重边的情况,那么本题就很水了。每个公司至少修一条路,在一次生成树计数中无法全部保证,就用容斥原理 O(2n) O ( 2 n ) 暴力计算即可。在很多计数问题中,约束条件无法在一次计算中全被保证,且约束个数较少,就可用容斥原理套路解决

代码

#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef pair pll;
const ll mod=1e9+7;
ll a,b,n,m,ans,cnt[20],G[20][20];
vector cache[20];
ll Gauss(ll n)
{
    ll det=1,flag=0;
    for(ll i=1;i<=n;i++)
    {
        for(ll j=i+1;j<=n;j++)
            while(G[j][i])
            {
                ll t=G[i][i]/G[j][i];
                for(ll k=i;k<=n;k++) G[i][k]=(G[i][k]-t*G[j][k]%mod+mod)%mod;
                swap(G[i],G[j]),flag^=1;
            }
        det=det*G[i][i]%mod;
    }
    if(flag) det=mod-det;
    return (det%mod+mod)%mod;
}
int main()
{
    scanf("%lld",&n);
    for(ll i=1;iscanf("%lld",&m);
        for(ll j=1;j<=m;j++) scanf("%lld%lld",&a,&b),cache[i].push_back(make_pair(a,b));
    }
    cnt[n-1]=1;
    for(ll i=n-2;i;i--) cnt[i]=-cnt[i+1];
    for(ll S=(1<1)-1;S;S--)
    {
        ll tot=0;
        memset(G,0,sizeof(G));
        for(ll i=1;iif(S&(1<<(i-1)))
                {
                    for(ll j=0;j1)%mod+mod)%mod;
    }
    printf("%lld\n",ans);
    return 0;
}

你可能感兴趣的:(线性代数,--------生成树计数,组合计数,--------容斥原理)