●洛谷P3687 [ZJOI2017]仙人掌
题链:
https://www.luogu.org/problemnew/show/P3687
题解:
计数DP,树形DP。
(首先对于这个图来说,如果初始就不是仙人掌,那么就直接输出0)
然后由于本来图中就存在于环中的边,不可能再次被包含,
所以图中的环就把这个图分为的若干颗树。
那么答案就是分别求出每颗树的方案数并相乘。
现在问题变为了求:把一颗树通过连边使得仍然是仙人掌的方案数。
定义如下3个数组:
f[u]:表示u这颗子树中没有一条从u到子树内某个的节点的路径可以向其它子树连边的方案数。
g[u]:表示u这颗子树中有一条从u到子树内某个节点的路径可以其它子树连边的方案数。
以及一个预处理的h[n]:
表示有n个元素,每个元素可以选择另一个元素与其两两匹配或者该元素不与任何元素匹配的方案数。
先看看h[n]的求法:
h[n]=h[n-1]+h[n-2]*(n-1)
即表明第n个元素要么独立,要么与另外(n-1)个元素中的某一个匹配。
然后看看怎样DP:
对于当前的子树的根u,v是其儿子节点,num是其儿子节点个数
$$f[u]=\sum g[v] \times h[num] $$
因为num个儿子有h[num]种匹配方案数,所以乘上h[num]
(所谓的匹配就是把g[v]中的那条路径的末端和与它匹配的那个v'的g[v']中的那条路径的末端连边)
然后还要求出当前的g[u]:
$$g[u]=f[u]+\sum g[v] \times h[num-1] \times num$$
含义如下:
由于u点自己可以成为g[u]中的那条路径的末端,所以$$+f[u]$$
然后u还可以选择一个儿子g[son]中的路径来连上自己形成新的g[u]中的路径。
这样的话,方案数是 $g[son]* \sum_{v!=son} g[v] \times h[num-1] = \sum g[v] \times h[num-1]$
又因为u有num个儿子,即有num中选法,所以:
$$+\sum g[v] \times h[num-1] \times num $$
代码:
#include<bits/stdc++.h>
#define MAXN 500005
#define MOD 998244353
#define rint register int
using namespace std;
int Case,N,M,dnt,cactus,ANS;
int dfn[MAXN],lu[MAXN],fa[MAXN],f[MAXN],g[MAXN],h[MAXN];
struct node{
int id,odr;
bool operator < (const node &rtm) const{
return odr<rtm.odr;
}
}A[MAXN];
struct Edge{
int ent;
int to[MAXN*4],nxt[MAXN*4],head[MAXN];
void Reset(int n){
for(rint i=1;i<=n;i++) head[i]=0; ent=2;
}
void Adde(int u,int v){
to[ent]=v; nxt[ent]=head[u]; head[u]=ent++;
}
}E;
void dfs(int u,int dad){
dfn[u]=++dnt; fa[u]=dad;
for(int e=E.head[u];e;e=E.nxt[e]){
int v=E.to[e];
if(dfn[v]) continue;
dfs(v,u);
}
}
void DP(int u,int rt){
lu[u]=-1; f[u]=1; int num=0,gson=1;
for(int e=E.head[u];e;e=E.nxt[e]){
int v=E.to[e];
if(lu[v]!=1||v==fa[u]) continue;
DP(v,0); num++;
gson=1ll*gson*g[v]%MOD;
}
f[u]=1ll*gson*h[num]%MOD;
g[u]=(1ll*f[u]+1ll*gson*h[num-1]%MOD*num)%MOD;
}
int main(){
h[0]=h[1]=1;
for(int i=1;i<=500000;i++) h[i]=(1ll*h[i-1]+1ll*h[i-2]*(i-1))%MOD;
for(scanf("%d",&Case);Case;Case--){
scanf("%d%d",&N,&M);
E.Reset(N); dnt=0; cactus=1; ANS=1;
for(rint i=1;i<=N;i++) lu[i]=dfn[i]=fa[i]=0;
for(int i=1,a,b;i<=M;i++)
scanf("%d%d",&a,&b),E.Adde(a,b),E.Adde(b,a);
dfs(1,0);
for(int e=1,u,v;e<=M;e++){
u=E.to[e*2]; v=E.to[e*2+1];
if(dfn[u]>dfn[v]) swap(u,v);
while(v!=u){
lu[v]++;
if(lu[v]>2){cactus=0;break;}
v=fa[v];
}
}
if(!cactus){printf("%d\n",0); continue;}
for(int i=1;i<=N;i++) A[i]=(node){i,dfn[i]};
sort(A+1,A+N+1);
for(int i=1,u;i<=N;i++){
u=A[i].id;
if(lu[u]==-1) continue;
DP(u,1); ANS=1ll*ANS*f[u]%MOD;
}
printf("%d\n",ANS);
}
return 0;
}
●洛谷P3687 [ZJOI2017]仙人掌的更多相关文章
- 洛谷 P4244 [SHOI2008]仙人掌图 II 解题报告
P4244 [SHOI2008]仙人掌图 II 题目背景 题目这个II是和SHOI2006的仙人掌图区分的,bzoj没有. 但是实际上还是和bzoj1023是一个题目的. 题目描述 如果某个无向连通图 ...
- 洛谷P4244 [SHOI2008]仙人掌图 II
传送门 首先不考虑带环的仙人掌,如果只是一棵普通的树,可以通过dp求每棵子树中的最长链和次长链求树的直径. 那么如果dfs的时候遇到了环,应该用环上的两点挂着的最长链加上两点间的距离来更新树的直径,并 ...
- ●洛谷P3688 [ZJOI2017]树状数组
题链: https://www.luogu.org/problemnew/show/P3688题解: 二维线段树. 先不看询问时l=1的特殊情况. 对于一个询问(l,r),如果要让错误的程序得到正确答 ...
- 2018.10.29 洛谷P4129 [SHOI2006]仙人掌(仙人掌+高精度)
传送门 显然求出每一个环的大小. Ans=∏i(siz[i]+1)Ans=\prod_i(siz[i]+1)Ans=∏i(siz[i]+1) 注意用高精度存答案. 代码: #include<b ...
- 洛谷P5211 [ZJOI2017]字符串(线段树+乱搞)
题面 传送门 题解 为什么大佬们全都是乱搞的--莫非这就是传说中的暴力能进队,乱搞能AC-- 似乎有位大佬能有纯暴力+玄学优化\(AC\)(不算上\(uoj\)的\(Hack\)数据的话--这要是放到 ...
- 洛谷 P3688 - [ZJOI2017]树状数组(二维线段树+标记永久化)
题面传送门 首先学过树状数组的应该都知道,将树状数组方向写反等价于前缀和 \(\to\) 后缀和,因此题目中伪代码的区间求和实质上是 \(sum[l-1...n]-sum[r...n]=sum[l-1 ...
- 洛谷P3688/uoj#291. [ZJOI2017]树状数组
传送门(uoj) 传送门(洛谷) 这里是题解以及我的卡常数历程 话说后面那几组数据莫不是lxl出的这么毒 首先不难发现这个东西把查询前缀和变成了查询后缀和,结果就是查了\([l-1,r-1]\)的区间 ...
- 【BZOJ4784】[ZJOI2017]仙人掌(Tarjan,动态规划)
[BZOJ4784][ZJOI2017]仙人掌(Tarjan,动态规划) 题面 BZOJ 洛谷 题解 显然如果原图不是仙人掌就无解. 如果原图是仙人掌,显然就是把环上的边给去掉,变成若干森林连边成为仙 ...
- [洛谷日报第62期]Splay简易教程 (转载)
本文发布于洛谷日报,特约作者:tiger0132 原地址 分割线下为copy的内容 [洛谷日报第62期]Splay简易教程 洛谷科技 18-10-0223:31 简介 二叉排序树(Binary Sor ...
随机推荐
- 网络1712--c语言字符数组作业总结..
---恢复内容开始--- 作业亮点 1.总体情况 1.大部分同学利用了流程图后,对于思路的理解有了提升. 2.很多同学在总结方面写的很不错,能够罗列问题贴出解决问题,我们能够看到你们的进步 2.作业发 ...
- 1013团队Beta冲刺day3
项目进展 李明皇 今天解决的进度 完善了程序的运行逻辑(消息提示框等) 明天安排 前后端联动调试 林翔 今天解决的进度 向微信官方申请登录验证session以维护登录态 明天安排 继续完成维护登录态 ...
- 冲刺NO.2
Alpha冲刺第二天 站立式会议 项目进展 团队成员在确定了所需技术之后,开始学习相关技术的使用,其中包括了HTML5,CSS与SSH框架等开发技术.并且在项目分工配合加以总结和完善,对现有发现的关于 ...
- win10 安装mingw ruby rails
原文可以参考 https://ruby-china.org/topics/17581 在window10 安装ruby rails https://rubyinstaller.org/download ...
- 第二篇:利用shell脚本执行webservice请求——基于soap
1. 项目背景 以往我们在开发基于webservice的项目中,我们总习惯于直接使用webservice的一些框架,如Axis,axis2和Xfire等.框架的好处是将webservice所涉及到的s ...
- c++ 中lambda
C++ 11中的Lambda表达式用于定义并创建匿名的函数对象,以简化编程工作. 1.Lambda表达式完整的声明格式如下: [capture list] (params list) mutable ...
- Mysql-5.7.21安装配置
搞开发多年,其实MySql前前后后安装配置了无数次,但是每次都需要到网上搜教程,折腾半天才搞定,这次索性把整个过程全部记录下来,以便以后查阅. 下载 到MySql官网,导航找到DOWNLOADS> ...
- 基于 Java NIO 实现简单的 HTTP 服务器
1.简介 本文是上一篇文章实践篇,在上一篇文章中,我分析了选择器 Selector 的原理.本篇文章,我们来说说 Selector 的应用,如标题所示,这里我基于 Java NIO 实现了一个简单的 ...
- python 单例模式的四种创建方式
单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. ...
- Windows用户模式下注入方式总结
注入技术在病毒木马.游戏.打补丁等编程中应用很广泛,学习该技术不仅能帮助理解Windows工作原理,还能对病毒木马技术手段有更加深刻的理解,下面我们了解下各种注入方式吧. 一.DLL注入 在注入技术中 ...