题目

给定一个简单无向连通图,问有多少种加边方案使得这个图变成简单仙人掌。


分析

首先找到一棵生成树,考虑其它非树边所对应的树的路径上的边最多只能用一次,

这可以用树上差分做,如果一个点到其父节点的边被用了多次就一定无解。

否则没有被用过的部分将形成若干棵树,方案就是它们的乘积。

等于说问用若干条路径覆盖一棵树的方案。

设 \(dp[x]\) 表示以 \(x\) 为根的子树的方案数。

只需要考虑 \(x\) 的邻边如何连接,子树的答案直接相乘。

设 \(f[n]\) 表示 \(n\) 条边任意匹配的方案数,则

\(f[n]=f[n-2]*(n-1)+f[n-1]\)

那么 \(dp[x]*=f[deg[x]]\)


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=500011,mod=998244353; struct node{int y,next;}e[N<<1],E[N<<1];
int f[N],c[N],v[N],as[N],hs[N],et=1,Et=1,n,dp[N],ans,fat[N],g[N],flag,upd,Lca[N<<1];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline signed getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
inline void Clear(){
for (rr int i=1;i<=n;++i) c[i]=as[i]=hs[i]=0;
}
inline void dfs1(int x,int fa){
f[x]=x,v[x]=upd,fat[x]=fa;
for (rr int i=as[x];i;i=e[i].next)
if (e[i].y!=fa) dfs1(e[i].y,x),f[e[i].y]=x;
for (rr int i=hs[x];i;i=E[i].next)
if (v[E[i].y]==upd) Lca[i]=Lca[i^1]=getf(E[i].y);
}
inline void dfs2(int x,int fa){
for (rr int i=as[x];i;i=e[i].next)
if (e[i].y!=fa) dfs2(e[i].y,x),c[x]+=c[e[i].y];
}
inline void dfs3(int x,int TOP){
rr int sub=0; dp[x]=1;
for (rr int i=as[x];i;i=e[i].next)
if (e[i].y!=fat[x]){
if (!c[e[i].y]) dfs3(e[i].y,TOP),++sub,dp[x]=1ll*dp[x]*dp[e[i].y]%mod;
else dfs3(e[i].y,e[i].y);
}
if (x==TOP) ans=1ll*ans*dp[x]%mod*g[sub]%mod;
else dp[x]=1ll*dp[x]*g[sub+1]%mod;
}
signed main(){
g[0]=g[1]=1;
for (rr int i=2;i<N;++i) g[i]=(g[i-2]*(i-1ll)+g[i-1])%mod;
for (rr int T=iut();T;--T,putchar(10)){
n=iut(),et=Et=ans=flag=1,++upd;
for (rr int i=1;i<=n;++i) f[i]=i;
for (rr int TOT=iut();TOT;--TOT){
rr int x=iut(),y=iut();
if (getf(x)!=getf(y)){
rr int fa=getf(x),fb=getf(y);
if (fa>fb) fa^=fb,fb^=fa,fa^=fb;
f[fa]=fb;
e[++et]=(node){y,as[x]},as[x]=et;
e[++et]=(node){x,as[y]},as[y]=et;
}else{
E[++Et]=(node){y,hs[x]},hs[x]=Et;
E[++Et]=(node){x,hs[y]},hs[y]=Et;
}
}
dfs1(1,0);
for (rr int i=2;i<=Et;i+=2)
++c[E[i].y],++c[E[i^1].y],c[Lca[i]]-=2;
dfs2(1,0);
for (rr int i=1;i<=n&&flag;++i)
if (c[i]>1) putchar(48),flag=0;
if (!flag) {Clear(); continue;}
dfs3(1,1),print(ans),Clear();
}
return 0;
}

#树形dp#洛谷 3687 [ZJOI2017]仙人掌的更多相关文章

  1. ●洛谷P3687 [ZJOI2017]仙人掌

    题链: https://www.luogu.org/problemnew/show/P3687题解: 计数DP,树形DP. (首先对于这个图来说,如果初始就不是仙人掌,那么就直接输出0) 然后由于本来 ...

  2. 树形DP 洛谷P2014 选课

    洛谷P2014 选课 题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门 ...

  3. 洛谷 P4244 [SHOI2008]仙人掌图 II 解题报告

    P4244 [SHOI2008]仙人掌图 II 题目背景 题目这个II是和SHOI2006的仙人掌图区分的,bzoj没有. 但是实际上还是和bzoj1023是一个题目的. 题目描述 如果某个无向连通图 ...

  4. 洛谷P4244 [SHOI2008]仙人掌图 II

    传送门 首先不考虑带环的仙人掌,如果只是一棵普通的树,可以通过dp求每棵子树中的最长链和次长链求树的直径. 那么如果dfs的时候遇到了环,应该用环上的两点挂着的最长链加上两点间的距离来更新树的直径,并 ...

  5. 区间DP 洛谷P2858牛奶零食

    题目链接 题意:你有n个货物从1-n依次排列,每天可以从两侧选一个出来卖,卖的价格是当天的天数乘该货物的初始价格,问这批货物卖完的最大价格 输入:第一行n,之后是n个货物的初始价值 这道题不能用贪心做 ...

  6. P1279 字串距离 dp 洛谷

    题目描述 设有字符串X,我们称在X的头尾及中间插入任意多个空格后构成的新字符串为X的扩展串,如字符串X为”abcbcd”,则字符串“abcb□cd”,“□a□bcbcd□”和“abcb□cd□”都是X ...

  7. dp 洛谷P1977 出租车拼车 线性dp

    题目背景 话说小 x 有一次去参加比赛,虽然学校离比赛地点不太远,但小 x 还是想坐 出租车去.大学城的出租车总是比较另类,有“拼车”一说,也就是说,你一个人 坐车去,还是一堆人一起,总共需要支付的钱 ...

  8. 经典DP 洛谷p1880 石子合并

    https://www.luogu.org/problemnew/show/P1880 题目 题目描述 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新 ...

  9. [DP]洛谷P1115最大子段和

    题目来源 https://www.luogu.org/problemnew/show/P1115 题目描述 给出一段序列,选出其中连续且非空的一段使得这段和最大. 输入输出格式 输入格式: 第一行是一 ...

  10. 尼克的任务 dp 洛谷1280

    蒟蒻表示老久没看过dp题目了,,挺水的一道dp题目都没想出来,,, 首先设dp[i]表示从开始到i时间的最大空闲时间,用vector to[x] 表示从x点开始的任务结束时间,cnt[x]表示从x开始 ...

随机推荐

  1. Telegraph多线程下载器v0.5--tkinter

    介绍 最近在拿python写一点小工具,结合之前的多线程.线程池技术做了个GUI版的Telegraph图册批量下载工具. 因为开发平台是在Mac,虽然对Windows平台的也进行了打包,但最垃圾的Wi ...

  2. OpenCV开发笔记(六十六):红胖子8分钟带你总结形态学操作-膨胀、腐蚀、开运算、闭运算、梯度、顶帽、黑帽(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  3. windows下redis安装与使用

    下载 redis下载地址 步骤,一直下一步按就完事了,记得勾选添加到环境配置 其中建议自定义路径吧,文件夹名字Redis,一定要大写,小写不来事. 安装完后 启动命令 找到你安装redis的文件夹,在 ...

  4. python模块imghdr-----推测图像类型

    官方文档 https://docs.python.org/zh-cn/3/library/imghdr.html#module-imghdr 用处 模块推测文件或字节流中的图像的类型 imghdr.w ...

  5. 【LeetCode贪心#06】加油站(股票买卖变种)

    加油站 力扣题目链接(opens new window) 在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升. 你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 ...

  6. 面试官上来就让手撕HashMap的7种遍历方式,当场愣住,最后只写出了3种

    写在开头 今天有个小伙伴私信诉苦,说面试官上来就让他手撕HashMap的7种遍历方式,最终只写出3种常用的,怀疑面试官是在故意***难.这个问题大家怎么看? 反正我个人感觉这肯定不是***难,&quo ...

  7. Java 接口:比较对象的大小

    1 package com.bytezreo.interfacetest; 2 3 /** 4 * 5 * @Description 接口:比较对象的大小 6 * @author Bytezero·z ...

  8. putty配置kali linux 远程连接

    首先配置sshd_config文件 VI 编辑或者使用 gedit 文本编辑, 修改的内容包括下面几个 红色标出(为了以复原建议大家 拷贝一份或者修改的地方进行标注) 之后重启服务,但是有的还是存在报 ...

  9. 使用Mockito与Squaretest进行单元测试.

    项目开发过程中,不少公司都要求写单元测试的代码,可以提高代码的质量,并且可以减少出现BUG的概率. 对于中小型公司来说,对单元测试不做硬性要求,不写最好.因为还是需要一定的工作量,在保证代码质量和性能 ...

  10. C#使用Stateless和箭头控件实现状态机的控制及显示

    之前开发一个小工具,内部实现一个状态机,并显示状态机当前状态及状态间的转移过程.我使用了Stateless开源类库及一个开源自定义箭头控件.自定义箭头控件是HZHControls其中一个控件,我单独把 ...