[ZJOI2016]小星星&[SHOI2016]黑暗前的幻想乡(容斥)
这两道题思路比较像,所以把他们放到一块。
[ZJOI2016]小星星
题目描述
小Y是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品。她有n颗小星星,用m条彩色的细线串了起来,每条细线连着两颗小星星。
有一天她发现,她的饰品被破坏了,很多细线都被拆掉了。这个饰品只剩下了n-1条细线,但通过这些细线,这颗小星星还是被串在一起,也就是这些小星星通过这些细线形成了树。小Y找到了这个饰品的设计图纸,她想知道现在饰品中的小星星对应着原来图纸上的哪些小星星。如果现在饰品中两颗小星星有细线相连,那么要求对应的小星星原来的图纸上也有细线相连。小Y想知道有多少种可能的对应方式。
只有你告诉了她正确的答案,她才会把小饰品做为礼物送给你呢。
题解
做容斥题有一个基本模型,就是有一个限制,我们直接在转移或者统计复杂度过高,但如果把它放宽一点的话复杂度会降低许多。
然后总的条件数也支持2^n枚举,就可以去考虑容斥。
这个题是说,有一个n个点的无向图和n个点的一棵树,问有多少种一一对应的映射使得在树中有的边,图中也有。
看到树可以联想树形dp,因为我们要求一一对应,所以我们可以考虑设dp[i][j][s]表示以i为根的子树,i对应了图中的j,i子树对应了图中的集合s的方案数。
转移还是比较简单的。
我们观察到这个算法复杂度瓶颈在于枚举s,所以我们考虑能不能去掉。
去掉之后会出现树中的多个点对应了图中的一个点,方案数会算多。
怎么办?这个形式其实已经很明显了,直接套用容斥公式算就好了。
2^n枚举图中选那些点,然后做二维的树形dp就好了。
代码
#include<iostream>
#include<cstdio>
#define N 18
#define R register
using namespace std;
typedef long long ll;
int n,m,tot,head[N],cou[<<N];
ll dp[N][N],ans;
bool a[N][N],jin[N];
inline int rd(){
int x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
struct edge{int n,to;}e[N*N*];
inline void add(int u,int v){
e[++tot].n=head[u];e[tot].to=v;head[u]=tot;
}
void dfs(int u,int fa){
for(R int i=;i<=n;++i)if(!jin[i])dp[u][i]=;else dp[u][i]=;
for(R int i=head[u];i;i=e[i].n)if(e[i].to!=fa){
int v=e[i].to;dfs(v,u);
for(R int j=;j<=n;++j)if(!jin[j]){
ll num=;
for(R int k=;k<=n;++k)if(a[j][k]&&!jin[k])num+=dp[v][k];
dp[u][j]*=num;
}
}
}
int main(){
n=rd();m=rd();int x,y;
for(R int i=;i<=m;++i){
x=rd();y=rd();
a[x][y]=a[y][x]=;
}
for(R int i=;i<n;++i){x=rd();y=rd();add(x,y);add(y,x);}
for(R int i=;i<(<<n);++i){
cou[i]=cou[i>>]+(i&);
for(R int j=;j<=n;++j)jin[j]=(i&(<<j-))!=;
dfs(,);
ll num=;
for(R int j=;j<=n;++j)num+=dp[][j];
if(cou[i]&)ans-=num;else ans+=num;
}
cout<<ans;
return ;
}
[SHOI2016]黑暗前的幻想乡
题目描述
四年一度的幻想乡大选开始了,最近幻想乡最大的问题是很多来历不明的妖怪涌入了幻想乡,扰乱了幻想乡昔日的秩序。但是幻想乡的建制派妖怪(人类)博丽灵梦和八云紫等人整日高谈所有妖怪平等,幻想乡多元化等等,对于幻想乡目前面临的种种大问题却给不出合理的解决方案。
风见幽香是幻想乡里少有的意识到了问题严重性的大妖怪。她这次勇敢地站了出来参加幻想乡大选,提出包括在幻想乡边境建墙(并让人类出钱),大力开展基础设施建设挽回失业率等一系列方案,成为了大选年出人意料的黑马并顺利地当上了幻想乡的大统领。
幽香上台以后,第一项措施就是要修建幻想乡的公路。幻想乡一共有 nn 个城市,之前原来没有任何路。幽香向选民承诺要减税,所以她打算只修 n-1n−1条公路将这些城市连接起来。但是幻想乡有正好 n-1n−1 个建筑公司,每个建筑公司都想在修路地过程中获得一些好处。虽然这些建筑公司在选举前没有给幽香钱,幽香还是打算和他们搞好关系,因为她还指望他们帮她建墙。所以她打算让每个建筑公司都负责一条路来修。
每个建筑公司都告诉了幽香自己有能力负责修建的路是哪些城市之间的。所以幽香打算 n - 1n−1条能够连接幻想乡所有城市的边,然后每条边都交给一个能够负责该边的建筑公司修建,并且每个建筑公司都恰好修建一条边。
幽香现在想要知道一共有多少种可能的方案呢?两个方案不同当且仅当它们要么修的边的集合不同,要么边的分配方式不同。
题解
这题和上一题相似,有两个限制。
上一题是要满足树中和图中都要有某条边。
这题是要满足我们的生成树中,既要有n个不同的点,还要满足每种颜色的边个出现一次。
如果我们去掉第二个限制,那就变成了生成树计数问题,套用矩阵树定理即可。
然后我们发现面前的这个问题还是可以套用容斥公式直接计算的,于是这道题被愉快的解决了。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define N 18
using namespace std;
typedef long long ll;
const int mod=1e9+;
ll a[N][N];
int n,m,cou[<<N];
bool tag[N];
inline int rd(){
int x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
inline ll power(ll x,ll y){
ll ans=;
while(y){if(y&)ans=ans*x%mod;x=x*x%mod;y>>=;}
return ans;
}
struct node{int x,y;};
vector<node>vec[N];
inline ll ni(ll x){return power(x,mod-);}
inline ll gauss(ll tot){
ll ans=;
for(int i=;i<=tot;++i)
for(int j=i+;j<=tot;++j){
ll t=a[j][i]*ni(a[i][i])%mod;
for(int k=i;k<=tot;++k)a[j][k]=((a[j][k]-t*a[i][k])%mod+mod)%mod;
}
for(int i=;i<=tot;++i)ans=(ans*a[i][i]%mod+mod)%mod;
return ans;
}
inline ll work(){
memset(a,,sizeof(a));
for(int i=;i<n;++i)if(tag[i]){
for(int j=;j<vec[i].size();++j){
int x=vec[i][j].x,y=vec[i][j].y;
a[x][x]++;a[y][y]++;a[x][y]--;a[y][x]--;
}
}
return gauss(n-);
}
int main(){
n=rd();int x,y;
for(int i=;i<n;++i){
m=rd();
for(int j=;j<=m;++j){
x=rd();y=rd();vec[i].push_back(node{x,y});
}
}
ll ans=;
for(int i=;i<(<<n-);++i){
cou[i]=cou[i>>]+(i&);
for(int j=;j<=n-;++j)tag[j]=(i&(<<j-))==;
if(cou[i]&)ans-=work();else ans+=work();
ans=(ans%mod+mod)%mod;
}
cout<<ans;
return ;
}
[ZJOI2016]小星星&[SHOI2016]黑暗前的幻想乡(容斥)的更多相关文章
- 【BZOJ4596】[Shoi2016]黑暗前的幻想乡 容斥+矩阵树定理
[BZOJ4596][Shoi2016]黑暗前的幻想乡 Description 幽香上台以后,第一项措施就是要修建幻想乡的公路.幻想乡有 N 个城市,之间原来没有任何路.幽香向选民承诺要减税,所以她打 ...
- BZOJ 4596: [Shoi2016]黑暗前的幻想乡(容斥+Matrix_Tree)
传送门 解题思路 看到计数想容斥--\(from\) \(shadowice1984\)大爷.首先求出原图的生成树个数比较容易,直接上矩阵树定理,但这样会多算一点东西,会把\(n-2\)个公司的多算进 ...
- 洛谷 P4336 黑暗前的幻想乡 —— 容斥+矩阵树定理
题目:https://www.luogu.org/problemnew/show/P4336 当作考试题了,然而没想出来,呵呵. 其实不是二分图完美匹配方案数,而是矩阵树定理+容斥... 就是先放上所 ...
- bzoj 4596 [Shoi2016]黑暗前的幻想乡 矩阵树定理+容斥
4596: [Shoi2016]黑暗前的幻想乡 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 559 Solved: 325[Submit][Sta ...
- bzoj4596[Shoi2016]黑暗前的幻想乡 Matrix定理+容斥原理
4596: [Shoi2016]黑暗前的幻想乡 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 464 Solved: 264[Submit][Sta ...
- P4336 [SHOI2016]黑暗前的幻想乡
P4336 [SHOI2016]黑暗前的幻想乡 矩阵树定理(高斯消元+乘法逆元)+容斥 ans=总方案数 -(公司1未参加方案数 ∪ 公司2未参加方案数 ∪ 公司3未参加方案数 ∪ ...... ∪ ...
- 【BZOJ 4596】 4596: [Shoi2016]黑暗前的幻想乡 (容斥原理+矩阵树定理)
4596: [Shoi2016]黑暗前的幻想乡 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 324 Solved: 187 Description ...
- bzoj4596/luoguP4336 [SHOI2016]黑暗前的幻想乡(矩阵树定理,容斥)
bzoj4596/luoguP4336 [SHOI2016]黑暗前的幻想乡(矩阵树定理,容斥) bzoj Luogu 题解时间 看一看数据范围,求生成树个数毫无疑问直接上矩阵树定理. 但是要求每条边都 ...
- BZOJ4596: [Shoi2016]黑暗前的幻想乡
Description 四年一度的幻想乡大选开始了,最近幻想乡最大的问题是很多来历不明的妖 怪涌入了幻想乡,扰乱了幻想乡昔日的秩序.但是幻想乡的建制派妖怪(人类) 博丽灵梦和八云紫等人整日高谈所有妖怪 ...
随机推荐
- 查看mysql数据库连接数、并发数相关信息
查看mysql数据库连接数.并发数相关信息. - caodongfang126的博客 - CSDN博客 https://blog.csdn.net/caodongfang126/article/det ...
- POJ_1185_炮兵阵地 dp+状态压缩
题目:炮兵阵地 链接:http://poj.org/problem?id=1185 解题思路: 首先用 int 来表示每一行的情况,比如说第一行是k1,那么[ k1&(k1>>2) ...
- Farm Irrigation
题目:Farm Irrigation 题目链接:http://210.34.193.66:8080/vj/Problem.jsp?pid=1494 题目思路:并查集 #include<stdio ...
- Eclipse导入工程后出现中文乱码
Eclipse之所以会出现乱码问题是因为eclipse编辑器选择的编码规则是可变的.一般默认都是UTF-8或者GBK,当从外部导入的一个工程时,如果该工程的编码方式与eclipse中设置的编码方式不同 ...
- CLOUD SQL跟踪
CLOUD会自动在后台执行一些sql语句,所以追踪起来比较麻烦,需要加入一些过滤条件. 比如关键的CLIENTPROCESSID,加入后 ,就能过滤是哪个客户度执行的数据. 过滤数据.
- rpm和yum
RMP(红帽软件包管理器) RPM有点像Windows系统中的控制面板,会建立统一的数据库文件,详细记录软件信息并能够自动分析依赖关系. YUM(软件仓库)
- 关于 html input标签的几个常用操作
1.清除 input 标签默认样式 input { -moz-appearance: none; outline: 0; text-decoration: none; outline: none; b ...
- Vue 获得所选中目标的状态(checked)以及对应目标的数据,并进行相应的操作
一.我们现在要拿取购物车中选中商品的状态和该商品的所有数据或者id <ul v-if="shopList.list.length>0"> <li class ...
- linux audit审计(6)--audit永久生效的规则配置
定义reboot系统后,仍然生效的审计规则,有两种办法: 1.直接写入/etc/audit/audit.rules文件中,在service文件中需要加入ExecStartPost=-/sbin/aud ...
- umask 文件默认权限
参考资料 http://book.51cto.com/art/200709/57189.htm umask就是指定当前用户在建立文件或目录时候的属性默认值. linux-xdYUnA:~ # umas ...