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

Time Limit: 20 Sec  Memory Limit: 256 MB
Submit: 559  Solved: 325
[Submit][Status][Discuss]

Description

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

Input

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

Output

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

Sample Input

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

Sample Output

17

HINT

Source

By 佚名上传

容斥一下让哪几个公司来修就可以了,然后每次矩阵树定理求一下方案树就可以了。

这里是直接高斯消元的,没有辗转相除的形式,但是好像矩阵树是保证还是桌面回事,不需要的。

 #pragma GCC optimize(2)
#pragma G++ optimize(2)
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring> #define ll long long
#define N 22
#define mod 1000000007
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-;ch=getchar();}
while(isdigit(ch)){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return x*f;
} int n;
int a[N][N],f[N][N],ans;
int cnt,hed[N];
struct Node
{
int x,y,nxt;
}e[]; void add(int u,int x,int y)
{
e[++cnt].x=x;
e[cnt].y=y;
e[cnt].nxt=hed[u];
hed[u]=cnt;
}
int cal(int num)//矩阵树定理是每个点的度,若x-y有边则x,y -1,y,x -1然后消去一行,下三角消元
{
//这里好处是num为n-1了,已经减去一行了。
for (int i=;i<=num;i++)
for (int j=;j<=num;j++)
a[i][j]=f[i][j];
int ans=;
for (int i=;i<=num;i++)
{
for (int j=i+;j<=n;j++)
while(a[j][i])
{
int t=a[i][i]/a[j][i];
for (int k=i;k<=n;k++)a[i][k]=(a[i][k]-(ll)a[j][k]*t%mod)%mod;
for (int k=i;k<=n;k++)swap(a[i][k],a[j][k]);
ans=-ans;//ans去反是因为斜对角线上负数的个数
}
if(!a[i][i])return ;
ans=(ll)ans*a[i][i]%mod;
}
return ans;
}
void dfs(int x,int y)
{
if (x==n)//就n-1个人
{
(ans+=y*cal(n-))%=mod;
return;
}
dfs(x+,y); for (int i=hed[x];i!=-;i=e[i].nxt)
{
int u=e[i].x,v=e[i].y;
f[u][u]--,f[v][v]--,f[u][v]++,f[v][u]++;
}
dfs(x+,-y);
for (int i=hed[x];i!=-;i=e[i].nxt)
{
int u=e[i].x,v=e[i].y;
f[u][u]++,f[v][v]++,f[u][v]--,f[v][u]--;
}
}
int main()
{
memset(hed,-,sizeof(hed));
n=read();
for (int i=;i<n;i++)
{
int number=read();
for (int j=;j<=number;j++)
{
int x=read(),y=read();
add(i,x,y);
f[x][x]++,f[y][y]++,f[x][y]--,f[y][x]--;
}
}
dfs(,);
printf("%d\n",(ans%mod+mod)%mod);
}

bzoj 4596 [Shoi2016]黑暗前的幻想乡 矩阵树定理+容斥的更多相关文章

  1. [SHOI2016] 黑暗前的幻想乡 - 矩阵树定理,容斥

    #include <bits/stdc++.h> using namespace std; #define int long long const int N = 20; const in ...

  2. bzoj4596/luoguP4336 [SHOI2016]黑暗前的幻想乡(矩阵树定理,容斥)

    bzoj4596/luoguP4336 [SHOI2016]黑暗前的幻想乡(矩阵树定理,容斥) bzoj Luogu 题解时间 看一看数据范围,求生成树个数毫无疑问直接上矩阵树定理. 但是要求每条边都 ...

  3. Luogu P4336 [SHOI2016]黑暗前的幻想乡 矩阵树定理+容斥原理

    真是菜到爆炸....容斥写反(反正第一次写qwq) 题意:$n-1$个公司,每个公司可以连一些边,求每个边让不同公司连的生成树方案数. 矩阵树定理+容斥原理(注意到$n$不是很大) 枚举公司参与与否的 ...

  4. 【BZOJ4596】【Luogu P4336】 [SHOI2016]黑暗前的幻想乡 矩阵树定理,容斥

    同样是矩阵树定理的裸题.但是要解决它需要能够想到容斥才可以. \(20\)以内的数据范围一定要试试容斥的想法. #include <bits/stdc++.h> using namespa ...

  5. BZOJ 4596: [Shoi2016]黑暗前的幻想乡

    Sol 容斥原理+Matrix-Tree定理.容斥跟小星星那道题是一样的,然后...直接Matrix-Tree定理就可以了... 复杂度\(O(2^{n-1}n^3)\) PS:调了好久啊QAQ 明明 ...

  6. ●BZOJ 4596 [Shoi2016]黑暗前的幻想乡

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4596 题解: 容斥,矩阵树定理,矩阵行列式 先说说容斥:(一共有 N-1个公司) 令 f[i ...

  7. bzoj 4596: [Shoi2016]黑暗前的幻想乡【容斥原理+矩阵树定理】

    真是简单粗暴 把矩阵树定理的运算当成黑箱好了反正我不会 这样我们就可以在O(n^3)的时间内算出一个无向图的生成树个数了 然后题目要求每个工程队选一条路,这里可以考虑容斥原理:全选的方案数-不选工程队 ...

  8. BZOJ 4596: [Shoi2016]黑暗前的幻想乡(容斥+Matrix_Tree)

    传送门 解题思路 看到计数想容斥--\(from\) \(shadowice1984\)大爷.首先求出原图的生成树个数比较容易,直接上矩阵树定理,但这样会多算一点东西,会把\(n-2\)个公司的多算进 ...

  9. 【BZOJ 4596】 4596: [Shoi2016]黑暗前的幻想乡 (容斥原理+矩阵树定理)

    4596: [Shoi2016]黑暗前的幻想乡 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 324  Solved: 187 Description ...

随机推荐

  1. JavaScript学习日志:关于js分号

    javascript有自动添加分号的功能,但是不是所有情况都会自动添加,要区分: 1,如果语句独占一行 如果当前行内的语句能够被js正确解析,那么就会在句尾添加一个分号. (如何判断是否正确解析?你在 ...

  2. Mysql覆盖索引 covering index 或者 index coverage

    组合索引 提到组合索引,大家都知道"最左前缀"原则.例如,创建索引 idx_name_age (name,age) ,通常情况下,where age=50 或者 where age ...

  3. MySQL的char和varchar针对空格的处理

    MySQL的char和varchar存储和查询中包含空格的实验 MySQL版本 一.测试char包含空格的存储和查询 测试发现,存储的数据,char数据类型的右侧空格存储的时候被删除了,但是左侧空格还 ...

  4. linux_通配符

    通配符和正则表达式区别? 通配符用在用户命令行bash环境,而正则表达式用于linux三剑客(awk, sed, grep) 那,有哪些通配符? * 所有字符    五星 ls *.txt # 列举目 ...

  5. python_如何进行反向迭代和实现反向迭代?

    案例: 实现一个连续的浮点数发生器,FloatRange,根据给定范围(start, end) 和步进值,产生一些列的浮点数,例如:FloatRange(3,4,0.2),将产生下列序列: 正向:3. ...

  6. 腾讯工程师带你深入解析 MySQL binlog

    欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 本文由 腾讯云数据库内核团队 发布在云+社区 1.概述 binlog是Mysql sever层维护的一种二进制日志,与innodb引擎中的red ...

  7. Windows核心编程&内核对象

    1. 一个进程在初始化时,系统将会他分配一个空的句柄表,这个句柄表仅供内核对象使用,不供用户对象和GDI对象使用.进程在首次 初始化时,该句柄表为空.句柄表是一个由数据结构组成的数组,包含一个内核对象 ...

  8. Java多线程之线程的同步

    Java多线程之线程的同步 实际开发中我们也经常提到说线程安全问题,那么什么是线程安全问题呢? 线程不安全就是说在多线程编程中出现了错误情况,由于系统的线程调度具有一定的随机性,当使用多个线程来访问同 ...

  9. 添加FTP用户(vsftpd)

    1.环境:ftp为vsftp. 用户名为test.默认路径为/home/test 2.新建用户(当前是root用户) 运行命令:"useradd -d /home/test test&quo ...

  10. awk数组结合+=统计题

    awk增加统计列值为增加列数或进行运行结果统计,使用符号 + =.增加的结果赋给符号左边变量值,增加到变量的域在符号右边.例如将 $ 1加入变量total,表达式为toatl+=$1.列值增加很有用. ...