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

  这题首先注意到给定图中如果存在环其实对于答案是没有影响的。然后关键之处就在于两个 \(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 = ; }
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 = , k = ;
char c;
c = getchar();
while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * k;
} void pre()
{
g[] = g[] = ;
for(int i = ; i < maxn; ++ i) g[i] = (g[i - ] + (i - )*g[i - ]) % 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] + ; Tarjan(v);
}
return;
} void dfs(int u, int rt)
{
mark[u] = -; f[u] = ; int tot = ;
for(int i = E1.head[u]; i; i = E1.last[i])
{
int v = E1.to[i]; if(v == fa[u] || mark[v] != ) continue;
tot ++; dfs(v, ); f[u] = f[u] * f[v] % mod;
}
if(!rt) f[u] = f[u] * g[tot + ] % mod;
else f[u] = f[u] * g[tot] % mod;
return;
} void Work()
{
n = read(), m = read(); E1.cnp = ;
for(int i = ; i <= n; i ++) mark[i] = fa[i] = dep[i] = dfn[i] = E1.head[i] = ;
for(int i = ; i <= m; i ++)
{
int u = read(), v = read();
E1.add(u, v);
}
dep[] = ; Tarjan();
for(int i = ; i <= m; i ++)
{
int u = E1.to[i << ], v = E1.to[i << | ];
if(dfn[u] < dfn[v]) swap(u, v);
while(u != v)
{
if(mark[u] == ) { printf("0\n"); return; }
mark[u] ++; u = fa[u];
}
}
for(int i = ; i <= n; i ++) a[i].id = i, a[i].dep = dep[i];
sort(a + , a + n + , cmp); ans = ;
for(int i = ; i <= n; i ++)
{
int x = a[i].id; if(mark[x] == -) continue;
dfs(x, ); ans = ans * f[x] % mod;
}
printf("%lld\n", ans); return;
} signed main()
{
pre(); int T = read();
while(T --) Work();
return ;
}

  

【题解】ZJOI2017仙人掌的更多相关文章

  1. 【BZOJ4784】[ZJOI2017]仙人掌(Tarjan,动态规划)

    [BZOJ4784][ZJOI2017]仙人掌(Tarjan,动态规划) 题面 BZOJ 洛谷 题解 显然如果原图不是仙人掌就无解. 如果原图是仙人掌,显然就是把环上的边给去掉,变成若干森林连边成为仙 ...

  2. [BZOJ4784][ZJOI2017]仙人掌(树形DP)

    4784: [Zjoi2017]仙人掌 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 312  Solved: 181[Submit][Status] ...

  3. bzoj4784 [Zjoi2017]仙人掌

    Description 如果一个无自环无重边无向连通图的任意一条边最多属于一个简单环,我们就称之为仙人掌.所谓简单环即不经过重复的结点的环. 现在九条可怜手上有一张无自环无重边的无向连通图,但是她觉得 ...

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

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

  5. zjoi2017 仙人掌

    题解: 好难的dp啊...看题解看了好久才看懂 http://blog.csdn.net/akak__ii/article/details/65935711 如果一开始的图就不是仙人掌,答案显然为0, ...

  6. 【做题】ZJOI2017仙人掌——组合计数

    原文链接 https://www.cnblogs.com/cly-none/p/ZJOI2017cactus.html 给出一个\(n\)个点\(m\)条边的无向连通图,求有多少种加边方案,使得加完后 ...

  7. LOJ2250 [ZJOI2017] 仙人掌【树形DP】【DFS树】

    题目分析: 不难注意到仙人掌边可以删掉.在森林中考虑树形DP. 题目中说边不能重复,但我们可以在结束后没覆盖的边覆盖一个重复边,不改变方案数. 接着将所有的边接到当前点,然后每两个方案可以任意拼接.然 ...

  8. 2019.02.07 bzoj4784: [Zjoi2017]仙人掌(仙人掌+树形dp)

    传送门 题意:给一个无向连通图,问给它加边形成仙人掌的方案数. 思路: 先考虑给一棵树加边形成仙人掌的方案数. 这个显然可以做树形dp. fif_ifi​表示把iii为根的子树加边形成仙人掌的方案数. ...

  9. BZOJ4784 ZJOI2017仙人掌(树形dp+dfs树)

    首先考虑是棵树的话怎么做.可以发现相当于在树上选择一些长度>=2的路径使其没有交,同时也就相当于用一些没有交的路径覆盖整棵树. 那么设f[i]为覆盖i子树的方案数.转移时考虑包含根的路径.注意到 ...

随机推荐

  1. 高级同步器:同步屏障CyclicBarrier

    引自:http://ifeve.com/concurrency-cyclicbarrier/ 简介 CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier).它要做的 ...

  2. Sencha Themer

    Sencha Themer 1:介绍 在Ext JS中创建自定义主题一直是一项挑战.但是使用Sencha Themer,我们已经删除了所有的猜测工作,并添加了一个简单的图形界面来定制应用程序的任何方面 ...

  3. HTTP学习之HTTP基础

    学习HTTP技术,首先要了解它的在web通信中有哪些特点,起到什么作用.有哪些规范.都有什么功能. HTTP的特点 HTTP使用的是一种可靠的.快速响应的数据传输协议,用户一旦发起请求,Web服务器可 ...

  4. 015---Django的forms组件

    Django form表单   Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用 ...

  5. Go语言中的UDP应用

    Go语言中的UDP应用 Go语言中使用UDP是很方便的,net包提供了UDP和TCP的功能,这里使用UDP做了一个UDP广播,然后接收各个设备的返回信息.实现起来很快,总体感觉比使用C#中的UDP更优 ...

  6. POJ 3210 : Coins

    参考:https://blog.csdn.net/u010885899/article/details/46636523 http://kqwd.blog.163.com/blog/static/41 ...

  7. SET UPDATE TASK LOCAL (ローカル更新 )

    ローカル更新では.更新プログラムは要求を処理したのと同じワークプロセスによって実行されます.ダイアログユーザは更新が終了するまで待ってから追加データを入力しなければなりません.データベースへのアクセス ...

  8. javascript实现浏览器管理员工具鼠标获取Html元素 并生成 xpath

    javascript实现浏览器管理员工具鼠标获取Html元素 并生成 xpath 看看标题就被吓尿了,够长吧.让我们看看到底是个什么玩意.. 直接上图: 就是这个东东了,做为一个写爬虫的,有必要了解下 ...

  9. Centos7下lamp环境搭建的小笔记

    刚刚把校赛弄完,赛前在环境搭建上花了蛮多时间,也正好记一下笔记 0.首先更新源 清华大学开源镜像站的源 https://mirrors.tuna.tsinghua.edu.cn/help/centos ...

  10. stm32--USB(作为U盘)+FatFs的实现

    一.USB功能的添加(作为U盘) 添加文件 将官方库中的Library文件夹中的所有有效文件添加到工程中,分为4个文件夹: usb class为硬件相关(Library\Class): usb dri ...