cfgym100026Acodecircles
题意:
给定一个仙人掌,问有多少种划分点集的方案,使得每个点集内的点两两没有边。
做法
当时好像想了一会题意是不是仙人掌。后来想起来每条边在至多一个环就是仙人掌的定义。
首先考虑没有边的时候,等价于贝尔数,(不过当时没发现,用斯特林数求的)。贝尔数递推公式:枚举最后一个集合的元素:\(B_n=\sum \binom{n}{k}B_k\)。
如果有边,遇到这种有限制的,考虑容斥每条边,变成必须在同一个联通块。
仙人掌可以考虑建出圆方树。树上 \(dp\),记录一下联通块个数。
树上 \(dp\) 的合并,只需要考虑合并一条边
要么是圆点->方点。要么是方点->圆点。
这里我第一遍没编清楚。
根节点是圆点的时候:我是同时枚举了首尾两条边,还需要额外记录首尾是否联通。
根节点是方点的时候:我让合并的第一个圆点不考虑连边。
这样写起来就不太优美。实际上可以把第一条边归到方点的讨论中。
这里还有个方点 \(siz=2\) ,即一条边的情况需要特判。
我在第一遍写的时候,试图直接 \(for\) 枚举钦定了多少条边。但是忘了乘组合数。最后还不如手动展开写。
还要注意不联通:图论必须要注意的:连通性,重边自环
复杂度是 \(O(n^2)\) 的,但是为了好写,我写的 \(O(n^3)\)。
最后写了 \(20min\),调了 \(20min\)。
后面又因为不知道还要 \(freopen\) 再调了 \(30min\)。
总结
关键在于编一些分讨和细节的时候没有考虑全面。而且在想一些简单写法的时候,容易导致这种写法实现的功能和预期的不一样。
所以:想到做法之后,不仅要验证做法的正确性。
还要把细节(尤其是 \(dp\) 含义和转移)完全编明白。以及想到一个好写的写法之后,思考一下这个写法是否真的是对的。
关于\(bell\) 数和仙人掌的映射还没有建立到位。
\(bell\) 数:可区分的点,划分成若干集合。
仙人掌:每条边,在最多一个环。
图论必须要注意的:连通性,重边自环
仙人掌上 \(dp\) 转移:可以把一条边拆到一个点上。
调试:有好调的小样例,先输出调试(看不懂就输出)。
然后看题干,看漏写,看简单写法是否是等价实现。
接着根据思路的是否容易假:考虑对拍/静态调试/思考做法性质。
但是要注意:选择一个调试方法之前,优先考虑利用一些简单的手段/分析定位到错误的地方
这种树上 \(dfs\) 找环/仙人掌的题目,一定要记得在最开头判掉返祖边。
如果没有重边,可以直接 \(==fa\)。否则,\(vector\) 存 \(pair\), 比较编号。
写的比较好的一个仙人掌模板:
这个是狭义的仙人掌。判掉父亲边之后,如果 \(low[v]==dfn[u]\),就是环。否则就是一条边。
注意,不要判 \(stk[top]==v\),因为重边会需要建方点

浙公网安备 33010602011771号