[树] [HDU5830] Rikka with Subset II

来源:互联网 发布:linux echo 脚本 编辑:程序博客网 时间:2024/06/10 01:58

题目传送门
还是翻译:
题目描述

我们都知道,Rikka酱数学不好,勇太君担心这个情况,所以他给了六花同学一些数学题来练习,下面是其中的一道:
勇太桑有一棵有n个节点的树,树上的所有边长度都是1,对于这些点的一个非空子集SS的价值value(S)等于max(dis(u,v)),其中u,vSdis(u,v)表示u,v两点间距离。
容易发现,value(S)[0,n)。现在,对于K[0,n),勇太君想知道有多少S集合满足value(S)=K
这对于六花酱来说太难了,你能帮帮她吗?

输入 Input

第一行包含一个整数t1t100,表示测试数据组数,并有不超过5组数据n>100
对于每组测试数据,第一行一个正整数n1n3000,接下来的n1行,每行两个数uv,表示uv之间有一条边。

输出 Output

对于每组测试数据,输出一行n个数,第i个数表示满足value(S)=i1的非空集合个数,这个答案可能很大,所以输出答案模998244353.

我们知道,Rikka with Subset这道题是NTT,这道题应该不是。
(我就是闲的没事来看看……)
注意,选择x个点,这x个点未必连通。
好了怎么做?
暴力一点,枚举集合,一共2n1个,然后找到树上最长的路径,这样总复杂度是O(n2n)的……
(摔西瓜……)
现在换种思路,如果我们枚举所选集合中最长路径,然后往里加点不就好了,这样就是O(n2)的了。
如果我们确定了两个端点,那么这两个端点之间的点(只是在路径上)是随意加的,如果两点间距离为k,那么这样的方案数共有2k1种。
诶诶诶不对啊,我怎么少了这么多种?
不在路径上的点也可以进入集合并且不影响最长路径!
tree
如图所示的一棵树,如果选择了端点(7,9),则5810也可以进入集合。
这样枚举就不行了,我们还得沿着路径爬上去计算选择子树的情况……这样就是O(n3)的了。
我们换种方法,枚举中间点来消除子树对最长路径的影响。
诶中间点?如果中间是条边怎么办?
分情况讨论……
我们需要预处理出一个点向下j0jn2层的节点数,还要预处理出到一个点距离为j0jn2的节点数。第一个好办,一遍树DP即可,第二个……
得了直接BFS吧(flag)
好了我们知道了这些,然后就是统计答案了……
对于一个点x,如果他是这条路径的中点,我们可以知道这条路径两端位于距离x相等的位置上(如上图树中(4,6)1为中点),于是我们枚举一半的距离dis[1,n2],如果距x距离为dis上点数少于2,就可以停止枚举了,如果有,那么2dis距离的答案就可以加了……
加多少?
我们一定是从一个小的dis扩展到一个大的dis,那么小的dis中的点都可以加到大的dis所在集合中而不影响答案(如上图(2,3)(4,6)),这样就消除了子树的影响。
推一下,答案加上2pre(2r1r)。其中r表示距x的距离为dis的节点数,pre就是小的dis中的节点数。
上式中2r1表示任取距x的距离为dis的节点,但是一定最少取2个,所以减去r
但是我们会发现答案还是不对……
因为有几种情况没考虑到。
如上图中5点,它并不能做中点,可是统计时多加了,我们把它减去;
如果随意选择的话,2r1r中存在没有选择最长的端点的情况,可以发现这些情况都是选择了次长的端点,于是我们把这些点产生的情况减去。
这样有点作为中点的情况考虑完了……
下面就应该是无中点的情况了。
接着要统计pre,我们发现这种情况是不对称的,所以条件讨论瞬间就少了很多,因为边的中点作为中点,那么距这个点距离为x的点和距这个点的儿子的距离为x的点构成了答案,我们发现统计父亲时,儿子中的点可能被重复统计,所以我们要把它减去,然后这两个集合随便取即可,注意左右都要有点,因为取的是非空集合。
唉我去好崩溃啊……难怪就6个A的……
写代码是更崩溃的……
那个BFS可能被卡常过不去,劼劼劼写了个DFS但是没看懂……
在学校题库卡常成功但是HDU上卡不过去,所以请自觉DFS……
可是DFS跑的好快啊!明明时间复杂度一样……
总时间复杂度O(tn2),需要非常注意常数……(我输出优化都上了……)
UPD:能不能用树的点分治做?
树的点分治因为无法处理那个”如果选择了端点(7,9),则5810也可以进入集合。”的情况也挂了……或许是我太弱没想到,欢迎dalao提出更优的解法QAQ
Code