2019.02.07 bzoj4784: [Zjoi2017]仙人掌(仙人掌+树形dp)
传送门
题意:给一个无向连通图,问给它加边形成仙人掌的方案数。
思路:
先考虑给一棵树加边形成仙人掌的方案数。
这个显然可以做树形dp。
fif_ifi表示把iii为根的子树加边形成仙人掌的方案数。
然后有两种情况:
- iii点没有父亲
- iii点有父亲
对于第一种情况即iii是树根的情况,显然fi=(∏fv)∗g∣sonp∣f_i=(\prod f_v)*g_{|son_p|}fi=(∏fv)∗g∣sonp∣,其中gig_igi表示给iii个儿子两两配对(每个儿子可配可不配的方案数)。
对于第二种情况有可能把iii跟父亲连上的那条边拿来放进一个环里,因此把iii也看成一个允许配对的连通块即可,则fi=(∏fv)∗g∣sonp∣+1f_i=(\prod f_v)*g_{|son_p|+1}fi=(∏fv)∗g∣sonp∣+1
现在只需要预处理出ggg数组即可,我们再次用dpdpdp解决这个问题:
g0=g1=1,gi=gi−1+(i−1)gi−2,(i≥2)g_0=g_1=1,g_i=g_{i-1}+(i-1)g_{i-2},(i\ge2)g0=g1=1,gi=gi−1+(i−1)gi−2,(i≥2)
这个递推很简单。
于是我们就成功处理出了树的情况,现在只用考虑原图怎么搞。
- 原图不是一个仙人掌,puts(0)puts(0)puts(0)即可
- 原图是一个仙人掌,我们把所有在环上面的边都删掉就成了一个森林,把每棵树的方案数统计出来乘起来就是答案。
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
const int N=5e5+5,mod=998244353;
typedef long long ll;
inline int add(const int&a,const int&b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(const int&a,const int&b){return a>=b?a-b:a-b+mod;}
inline int mul(const int&a,const int&b){return (ll)a*b%mod;}
int n,m,dfn[N],low[N],tot=0,cnt[N],g[N],f[N],fa[N],siz;
bool vis[N],flag;
vector<int>e[N];
map<int,int>ban[N];
inline void solve(int rt,int p){
ban[rt][p]=ban[p][rt]=1;
while(p!=rt){
if(++cnt[p]==2){flag=0;return;}
ban[p][fa[p]]=ban[fa[p]][p]=1,p=fa[p];
}
}
void tarjan(int p){
++siz;
if(!flag)return;
dfn[p]=low[p]=++tot;
for(ri i=0,v;i<e[p].size();++i){
if((v=e[p][i])==fa[p])continue;
if(!flag)return;
if(!dfn[v])fa[v]=p,tarjan(v),low[p]=min(low[p],low[v]);
else low[p]=min(low[p],low[v]);
}
if(!flag)return;
for(ri i=0,v;i<e[p].size();++i)if(fa[v=e[p][i]]!=p&&dfn[p]<dfn[v])solve(p,v);
}
void dfs(int p,int fat){
vis[p]=1;
int du=0,mult=1;
for(ri i=0,v;i<e[p].size();++i){
if((v=e[p][i])==fat||ban[p][v])continue;
dfs(v,p),mult=mul(mult,f[v]),++du;
}
if(fat)f[p]=mul(mult,g[du+1]);
else f[p]=mul(mult,g[du]);
}
int main(){
g[0]=g[1]=1;
for(ri i=2;i<=500000;++i)g[i]=add(g[i-1],mul(g[i-2],i-1));
for(ri tt=read(),ans;tt;--tt){
n=read(),m=read(),flag=1,siz=0;
for(ri i=1;i<=n;++i)e[i].clear(),cnt[i]=dfn[i]=low[i]=vis[i]=0,ban[i].clear();
for(ri i=1,u,v;i<=m;++i)u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);
tarjan(1),ans=1;
if(!flag||siz<n){puts("0");continue;}
for(ri i=1;i<=n;++i)if(!vis[i])dfs(i,0),ans=mul(ans,f[i]);
cout<<ans<<'\n';
}
return 0;
}
2019.02.07 bzoj4784: [Zjoi2017]仙人掌(仙人掌+树形dp)的更多相关文章
- LOJ2250 [ZJOI2017] 仙人掌【树形DP】【DFS树】
题目分析: 不难注意到仙人掌边可以删掉.在森林中考虑树形DP. 题目中说边不能重复,但我们可以在结束后没覆盖的边覆盖一个重复边,不改变方案数. 接着将所有的边接到当前点,然后每两个方案可以任意拼接.然 ...
- Codeforces 980F Cactus to Tree 仙人掌 Tarjan 树形dp 单调队列
原文链接https://www.cnblogs.com/zhouzhendong/p/CF980F.html 题目传送门 - CF980F 题意 给定一个 $n$ 个节点 $m$ 条长为 $1$ 的边 ...
- 2019.02.07 bzoj4316: 小C的独立集(仙人掌+树形dp)
传送门 题意:给出一个仙人掌森林求其最大独立集. 思路:如果没有环可以用经典的树形dpdpdp解决. fi,0/1f_{i,0/1}fi,0/1表示第iii个点不选/选的最大独立集. 然后fi,0+ ...
- 2019.02.07 bzoj1487: [HNOI2009]无归岛(仙人掌+树形dp)
传送门 人脑转化条件过后的题意简述:给你一个仙人掌求最大带权独立集. 思路:跟这题没啥变化好吗?再写一遍加深记忆吧. 就是把每个环提出来分别枚举环在图中的最高点选还是不选分别dpdpdp一下即可,时间 ...
- BZOJ4784 ZJOI2017仙人掌(树形dp+dfs树)
首先考虑是棵树的话怎么做.可以发现相当于在树上选择一些长度>=2的路径使其没有交,同时也就相当于用一些没有交的路径覆盖整棵树. 那么设f[i]为覆盖i子树的方案数.转移时考虑包含根的路径.注意到 ...
- 洛谷 5291 [十二省联考2019]希望(52分)——思路+树形DP
题目:https://www.luogu.org/problemnew/show/P5291 考场上写了 16 分的.不过只得了 4 分. 对于一个救援范围,其中合法的点集也是一个连通块. 2n 枚举 ...
- 2019.02.09 bzoj4455: [Zjoi2016]小星星(容斥原理+dp)
传送门 题意简述:给一张图和一棵树(点数都为n≤17n \le17n≤17),问有多少种给树的标号方法方法使得图中去掉多余的边之后和树一模一样. 思路: 容斥好题啊. 考虑fi,jf_{i,j}fi, ...
- [BZOJ4784][ZJOI2017]仙人掌(树形DP)
4784: [Zjoi2017]仙人掌 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 312 Solved: 181[Submit][Status] ...
- bzoj4784 [Zjoi2017]仙人掌
Description 如果一个无自环无重边无向连通图的任意一条边最多属于一个简单环,我们就称之为仙人掌.所谓简单环即不经过重复的结点的环. 现在九条可怜手上有一张无自环无重边的无向连通图,但是她觉得 ...
随机推荐
- Git之生成SSH公钥
一 生成公钥 ssh-keygen -t rsa -C "michelangelo@qq.com" -t :密钥类型. -C : 注释.通常用作密钥的名字. 依次按三次回车:默认 ...
- f5故障排除
1.硬件问题 1)硬盘:查看/var/log/daemon, kern日志,smartctl测试,EUD 2)PSU: 查看LCD报警,/var/log/ltm,EUD等 3)内存:可能导致设备突然重 ...
- redis-storage介绍[转]
背景: 当时我们正在做一个游戏项目,游戏项目相比于web项目,更追求的是单机的性能,而我们对单个请求的处理时间有着bt级的需求(一个完整的api请求控制在10ms以内).当时我们的数据层用的是ttse ...
- 配置eclipse+SDK+ADT开发环境
第一步:配置jdk和eclipse环境(已完成): 第二步:ADT配置:依次点击菜单栏:help -> Install new software -> Add -> Local... ...
- day 11 生成器
生成器生成器本质就是迭代器,生成器是自己用python代码写的迭代器 将函数变成生成器yield用next 取值一个next,对应一个yield def func(): yield 111 yield ...
- Python 安装pyautogui
在Python中使用PyAutoGui模拟键盘和鼠标操作 一.系统环境 操作系统:win10 64位 Python版本:Python 3.7.0 二.安装参考 1.使用pip进行安装,pip inst ...
- 纯css实现div中未知尺寸图片的垂直居中
1.淘宝的方法 在曾经的"淘宝UED招聘"中有这样一道题目: “使用纯CSS实现未知尺寸的图片(但高宽都小于200px)在200px的正方形容器中水平和垂直居中.” 当然出题并不是 ...
- 整站变灰CSS代码
* { filter:progid:DXImageTransform.Microsoft.BasicImage(grayscale=1); -webkit-filter: grayscale(100% ...
- SSH Secure Shell链接Ubuntu报错Server responded "Algorithm negotiation failed"
vim /etc/ssh/sshd_config Ciphers aes128-cbc,aes192-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr,3 ...
- .netcore webapi iis 虚拟目录下载apk文件
首先贴上微软的文档:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/static-files 参考网址:http://www.cnb ...