感觉这题很厉害啊,虽然想了一天多但还是失败了……(;д;)

  这题首先注意到给定图中如果存在环其实对于答案是没有影响的。然后关键之处就在于两个 \(dp\) 数组,其中 \(f[u]\) 表示以 \(u\) 为根的子树中能构成仙人掌的方案数, 而 \( g[x] \) 则表示 \(x\) 个节点之间两两相互搭配(可以不搭配)的总方案数。转移则为:

 \(f[u] = \prod f[v] * g[tot + [u != root]]\)

  其中 \(v\) 为 \(u\) 的儿子节点,而 \(tot\) 表示 \(u\) 的总儿子个数。为什么这样做是对的呢?我也感到非常的困惑。之前自己在思考的时候其实有一个问题一直难住我:一个节点的儿子之间可以相互连边,这怎样处理?但此时我们将这些方案巧妙地连接在了一起。我们可以默认为求出来的 \(f[u]\) 中的方案数均为有一条边连向外界的方案。当这个方案匹配到另一子树的一种方案上的时候,表示这两条连向外界的边连接在了一起。若有没有匹配的,说明这条边没有连出去或连向根节点(若连向根节点且该点为儿子节点则说明没有连出去),但一样是合法的。

  非常的厉害啊~其实感觉自己现在各种知识储备都还算可以了,但就是不够大胆,不能勇敢的提出一些想法和设想。一定要努力放开自己的思维,先猜测,再证明~

#include <bits/stdc++.h>
using namespace std;
#define maxn 1000000
#define mod 998244353
#define int long long
int n, m, dep[maxn], g[maxn];
int timer, dfn[maxn], f[maxn];
int fa[maxn], mark[maxn], tot;
int cnt, ans;struct edge
{int cnp, head[maxn], to[maxn], last[maxn];edge() { cnp = 1; }void add(int u, int v){to[cnp] = v, last[cnp] = head[u], head[u] = cnp ++;to[cnp] = u, last[cnp] = head[v], head[v] = cnp ++;}
}E1;struct node
{int id, dep;
}a[maxn];bool cmp(node a, node b) { return a.dep < b.dep; }int read()
{int x = 0, k = 1;char c;c = getchar();while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();return x * k;
}void pre()
{g[0] = g[1] = 1;for(int i = 2; i < maxn; ++ i) g[i] = (g[i - 1] + (i - 1)*g[i - 2]) % mod;return;
}void Tarjan(int u)
{dfn[u] = ++ timer;for(int i = E1.head[u]; i; i = E1.last[i]){int v = E1.to[i]; if(dfn[v]) continue;fa[v] = u; dep[v] = dep[u] + 1; Tarjan(v);}return;
}void dfs(int u, int rt)
{mark[u] = -1; f[u] = 1; int tot = 0;for(int i = E1.head[u]; i; i = E1.last[i]){int v = E1.to[i]; if(v == fa[u] || mark[v] != 1) continue;tot ++; dfs(v, 0); f[u] = f[u] * f[v] % mod;}if(!rt) f[u] = f[u] * g[tot + 1] % mod;else f[u] = f[u] * g[tot] % mod;return;
}void Work()
{n = read(), m = read(); E1.cnp = 2;for(int i = 1; i <= n; i ++) mark[i] = fa[i] = dep[i] = dfn[i] = E1.head[i] = 0;for(int i = 1; i <= m; i ++){int u = read(), v = read();E1.add(u, v);}dep[1] = 1; Tarjan(1);for(int i = 1; i <= m; i ++){int u = E1.to[i << 1], v = E1.to[i << 1 | 1];if(dfn[u] < dfn[v]) swap(u, v);while(u != v) {if(mark[u] == 2) { printf("0\n"); return; }mark[u] ++; u = fa[u];}}for(int i = 1; i <= n; i ++) a[i].id = i, a[i].dep = dep[i];sort(a + 1, a + n + 1, cmp); ans = 1;for(int i = 1; i <= n; i ++){int x = a[i].id; if(mark[x] == -1) continue;dfs(x, 1); ans = ans * f[x] % mod;}printf("%lld\n", ans); return;
}signed main()
{pre(); int T = read();while(T --) Work();return 0;
}

  

转载于:https://www.cnblogs.com/twilight-sx/p/9230703.html

【题解】ZJOI2017仙人掌相关推荐

  1. [zjoi2017]仙人掌

    前言 谨以此题纪念我第一次参加省选时刚了5h这一题得到0分的经历 题目相关 链接 题目大意 给出仙人掌定义:如果一个无自环无重边无向连通图的任意一条边最多属于一个简单环,我们就称之为仙人掌 给出一个图 ...

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

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

  3. ZJOI2017 仙人掌

    题目大概是给个无向图,求添加边使其变为仙人掌的方案数. 直接判断是否仙人掌,特判输出0即可. 否则的话,把环拆开成链变成一个树,考虑暴力计算儿子的配对方案数,打表规律:\(f[i] = f[i - 1 ...

  4. BZOJ4784 [Zjoi2017]仙人掌

    标签:树形DP,tarjan,仙人掌 题目 题目传送门 Description 如果一个无自环无重边无向连通图的任意一条边最多属于一个简单环,我们就称之为仙人掌.所谓简单环即不经过重复的结点的环. 现 ...

  5. 【ZJOI2017】仙人掌 题解

    题目大意 ~~~~~~给出一个无重边无自环的无向连通图(n 个点 m 条边),问有多少种再往上加边的方案,使得新图是仙人掌.       ~~~~~~多组数据, n<=5e5, ∑m\sum m ...

  6. 【ZJOI2017】仙人掌

    题面 https://www.luogu.org/problem/P3687 题解 如果原图不是仙人掌(在这里,我们认为一棵树也是一个仙人掌),则无解,输出$0$. 如果原图是一个仙人掌,加的边是不能 ...

  7. BZOJ1023:[SHOI2008]仙人掌图——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=1023 Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple ...

  8. 动态仙人掌 系列题解之一——3464: 动态仙人掌 I

    (重发下我这篇原发于 2014-03-18 的网易博客,原博客被网易莫名禁掉了..被迫手动搬家,忧伤) 现在好像各种题目出树已经出烦了,开始出仙人掌了.什么时候咱们不出动态树了,搞个Link-Cut ...

  9. 动态仙人掌 系列题解之三——3466: 动态仙人掌 III

    (重发下我这篇原发于 2014-03-24 的网易博客,原博客被网易莫名禁掉了..被迫手动搬家,忧伤) 动态仙人掌 III 能link.cut.查询最短路信息.对最短路进行整体操作. 于是我们当然可以 ...

最新文章

  1. Angular cli 发布自定义组件
  2. Java数据结构和算法:HashMap的实现原理
  3. 亚信安全火力全开猎捕“坏兔子”,全歼详解
  4. Android菜鸟的成长笔记(5)——Android系统源代码你下载了吗?
  5. html引用单文件组件,vue之单文件组件 纯网页方式引入
  6. findbugs插件_Intellij静态代码扫描插件SpotBugs
  7. c++ primer plus中文版_如何成为一名厉害的C/C++程序员?
  8. 需要c语言,需要C语言的需要什么工具软件
  9. excel的ADO读取ORACLE,【VBA研究】利用ADO让普通人用excel读取oracle数据库表的通用办...
  10. 苹果mac微软windows远程连接工具:microsoft remote desktop
  11. 【机器人学习】平台并联机构matlab逆解
  12. matlab中rand函数用法
  13. 史上最全的点线面距离公式与推导过程(图文介绍)
  14. 史话下:量子物理学的前世今生
  15. SVG_16_defs标签_use标签_style标签_红绿灯效果
  16. Bandit算法学习[网站优化]02——epsilon-Greedy 算法
  17. windows 10环境下docker 部署RocketMq和RocketMq-Consol 控制台
  18. 【简单利用函数实现多条件求和】
  19. 因为此版本的应用程序不支持其项目类型(.csproj)
  20. 计算机屏幕纵向显示如何改,电脑桌面纵向怎么设置

热门文章

  1. 【java笔记】线程(3):Thread类的常用方法
  2. Flex+BlazeDs+Java的教程及Demo
  3. 如何运行wifi服务器,技术:如何通过wifi进行文件传输?
  4. 2个表 遍历 组合_7.2 图的存储结构(2)
  5. C# 根据url获取文件流流
  6. Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.1:test
  7. PowerDesigner显示Comment注释栏
  8. css设置div水平居中
  9. easyUI 动态参数名称和动态参数值
  10. Win7如何禁用无线网卡