题目

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


分析

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

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

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

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

设 \(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. 使用Gulp压缩静态资源

    如果希望对在静态页面中引入的相关资源进行压缩(比如:CSS,JavaScript,图片等),可以使用Gulp实现. 当然,还可以使用其他打包工具,比如:Grunt,Webpack等等. Gulp是什么 ...

  2. os.path.relpath和os.path.basename,返回文件路径中的文件名

    from os import path print(path.relpath("/home/hpcadmin/lw/demo.py", start="/home/hpca ...

  3. Python3中的“联动”现象

    技术背景 在python中定义一个列表时,我们一定要注意其中的可变对象的原理.虽然python的语法中没有指针,但是实际上定义一个列表变量时,是把变量名指到了一个可变对象上.如果此时我们定义另外一个变 ...

  4. 修改centos7虚拟机的用户密码

    在忘记原密码无法登录桌面的情况下,修改centos7的用户密码 非常规启动,进入编辑启动菜单 在启动GRUB菜单中选择编辑选项,按键e进入编辑; 找到linux16开头的一行,在该行中寻找ro的所在地 ...

  5. TR069-STUN

    原理 1.NAT穿越技术,为了解决NAT设备对P2P网络的通信限制   2.作用:检测网络中是否存在NAT设备,并获取两个通信端点经NAT设备分配的IP地址和端口号,然后建立一条可穿越NAT的P2P链 ...

  6. 幕布 和 xmind 的大纲模式 都很不错

    幕布 和 xmind 的大纲模式 都很不错 xmind 思维导图 ctrl+a 折叠所有子分支 然后就能一级一级展开 最后选择用 xmind的大纲模式,因为免费. 幕布收费,限300个节点,小数据量的 ...

  7. Spring 中不得不了解的姿势

    说明 本文非原创,我只是进行了整理以及做了一些改动,仅供学习,若需进行商业使用,请联系原作者 原作者:苏三 原文链接:苏三说技术:Spring系列 Spring IOC 本章节解读的流程为Spring ...

  8. 【预训练语言模型】BERT原理解析、常见问题和微调实战

    一.BERT原理 1.概述        背景:通过在大规模语料上预训练语言模型,可以显著提高其在NLP下游任务的表现.        动机:限制模型潜力的主要原因在于现有模型使用的都是单向的语言模型 ...

  9. Kotlin学习快速入门(12)—— 位运算符

    由于不懂pythod,最近拜托朋友研究下解密live2d模型的解密算法,朋友写出了Java的代码 之后我进行改版,在转为kotlin的时候,发现kotlin自动转换有些坑,以及kotlin中的位运算符 ...

  10. Eclipse之各个版本的区别

    经常用到的是前五个版本: Eclipse IDE for Java EE Developers:是为J2EE开发的版本: Eclipse Classic:是Eclipse的经典版本,没有安装任何插件, ...