题意
在一棵有根树中,边有两种:虚边和实边。一个点最多和一个儿子之间有实边。
当我们执行 Access(x) 时,首先会把 x 到根这条路径上的所有点的实边全变成虚边,然后把这条路径上的所有边全变成实边。
有一棵 n n n 个点、以 1 1 1 为根的有根树,一开始所有边都是虚边。你可以进行最多 k k k 次任意的 access 操作,求树有可能的形态数目。
子任务一 ( 30 30 30pts),树为一条链.
子任务二 ( 30 30 30pts),树随机生成.
子任务三 ( 40 40 40pts),无特殊限制.
对所有的数据, n ≤ 1 0 4 , k ≤ 500 n\le 10^4,k\le 500 n≤104,k≤500.
题解
吐槽:
考场上看错题(以为不会把x连下去的边变为轻边 ),用了3h调不过样例自闭了。(考场上看错题频率我自己都无语了,不能再相信自己的读题能力了,一定要手模样例!!!)
后来赶快想了个怪怪的DP,考试结束后一会才调出来(到底该如何快速地调DP题呢???)。之后更加自闭:交上去WA了???怎么还有计数题拍得好好的还挂了?不知道怀疑人生了多久,最后发现数组越界(你不RE是什么意思啊)。。。
最近做题背到怀疑人生,希望在攒人品吧。。。
正话:
感觉这题我的想法很垃圾吧,其它人都是一些比较优美的性质+DP。
看完题感觉很树形背包,又发现把一个点重复access
是没用的,于是直接记
f
[
i
]
[
j
]
f[i][j]
f[i][j]为
i
i
i子树access
了
j
j
j个点,
i
i
i子树内边的实或虚的方案数(简称形态),
j
j
j是
m
i
n
(
k
,
s
z
[
i
]
)
min(k,sz[i])
min(k,sz[i])内的,那就更树形背包了。
但有一个问题,就是可能在一个子树内access
不同的点数,造成的形态会相同,所以状态应改为保证这种形态不能通过把比
j
j
j更少的点数accsee
来形成。
考虑转移,先把子树的状态用背包合并到辅助数组
g
g
g上,发现有access
点的子树都可以作为最后一个操作的,把它伸上去的边变为实边,每种
g
g
g内的方案都要乘上它有access
的子树个数,于是用
g
g
g辅助
f
f
f的转移即可。再考虑把
u
u
uaccess
,会使
u
u
u伸下去的边都是虚边,于是加上
g
g
g的值即可。有一种特殊情况:如果一颗子树
v
v
v只access
v
v
v,并且以
v
v
v伸上来的边为实边,那么这种方案在
v
v
v中不会考虑到,所以要在转移
g
g
g的时候多记一维加上这种。发现上面的转移都可以保证形成的形态没有更优解(其实这样的考虑是在看错题的时候比较重要,当时想了很久想出来时还很激动,实在是弱智得不行),效率
O
(
n
k
)
O(nk)
O(nk)。