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 如果一个无自环无重边无向连通图的任意一条边最多属于一个简单环,我们就称之为仙人掌.所谓简单环即不经过重复的结点的环. 现在九条可怜手上有一张无自环无重边的无向连通图,但是她觉得 ...
随机推荐
- Sigar--系统性能监测
Sigar(System Information Gatherer And Reporter),是一个开源的工具,提供了跨平台的系统信息收集的API.可以收集的信息包括: 1, CPU信息,包括基本信 ...
- javascript根据身份证号判断精确周岁年龄
前言: 根据身份证号判断精确周岁年龄,可以精确到天,即周岁以生日当天为准,生日当天周岁+1,少一天则不加. 实现方法: <!DOCTYPE html> <html> <h ...
- HW3 纠结的心得
改好的controller //yuec2 Yue Cheng package hw3; import java.io.File; import java.text.DecimalFormat; im ...
- 有关https有的网站可以访问有的访问不了的问题
在开发中遇到这种情况,在开发工具里面访问可以,当时到了手机上之后就发现有的请求可以正常获取数据,有的则不行. 都是使用https地址,也配置后台了,但是就是不出数据,总是无法请求服务. 后来检查在手机 ...
- Non-negative Integers without Consecutive Ones
n位二进制,求不包含连续1的二进制(n位)数字个数. http://www.geeksforgeeks.org/count-number-binary-strings-without-consecut ...
- Js 怎么遍历json对象所有key及根据动态key获取值(根据key值获取相应的value值)
Js代码 <script type="text/javascript"> getJson('age'); function getJson(key){ var json ...
- org.springframework.web.util.Log4jWebConfigurer
org.springframework.web.util.Log4jWebConfigurer @Deprecated Deprecated. as of Spring 4.2.1, in favor ...
- sqlserver 分区排序之partition
例如:按照课程分组取各个课程最高成绩的记录,使用partition分区,然后按照成绩倒序排列,需要注意的是考虑到可能出现多个相同最高分,使用dense_rank来实现连续排序. 参考链接:https: ...
- 关于document的节点;用Dom2创建节点;
一.关于节点 1.节点树状图 document>documentElement>body>tagName 2.节点类型 元素节点(标签).文本节点(文本).属性节点(标签属性) 3. ...
- c# 关于取小数点后值四舍五入精度问题
---恢复内容开始--- 最近做一个校验码验证法算法的生成程序,涉及到取小数点后值的问题;对其中遇到的问题做一下总结: 1:ToString()转换时碰到0.9999999999999之类的数据,给自 ...