前不久,WC2019考了一道风格新奇的数树。
通过层层容斥化式猜结论,(子任务2)终于化简成了一道小清新树形DP:
一个边集T的权值等于每个连通块的权值之积,每个连通块的权值等于 k × k× k×联通块大小,求所有边集的权值之和。一个简单的实现方式是直接 d p dp dp,令 d p ( i , j ) dp(i,j) dp(i,j)表示划分到了 i i i这个子树, i i i所在的联通大小为 j j j时的所有边集权值之和,直接实现的复杂度是 O ( n 2 ) O(n^2) O(n2)的并不能通过 n = 1 0 5 n=10^5 n=105的诡异数据。
且不看最后一句话,这段话差点让我。。。。。。怎么 O ( n 2 ) O(n^2) O(n2)DP啊,一个n枚举点,一个n枚举当前大小,一个n枚举增加的大小,这活脱脱的 O ( n 3 ) O(n^3) O(n3)?然后我就naive了。原来大佬早有证明。具体是这样的,合并大小为a,b的子树复杂度是 O ( a b ) O(ab) O(ab),可以看成a子树内任选一点,b子树内任选一点进行匹配,不管怎么合并任意两个点只会在其lca匹配一次,所以是 O ( n 2 ) O(n^2) O(n2)的。
所以我的树形DP都白学了。。。。。。
其次,如果第二位大于k的部分不需要,那么复杂度是
O
(
n
k
)
O(nk)
O(nk)的
这就导致2018九省联考秘密袭击这道题的
O
(
n
2
k
)
O(n^2k)
O(n2k)大力树上DP远远快于我的
O
(
n
2
log
2
n
)
O(n^2\log^2 n)
O(n2log2n)的FFT和
O
(
n
2
log
n
)
O(n^2\log n)
O(n2logn)的线段树合并维护整体DP+拉格朗日插值
O
(
n
2
)
O(n^2)
O(n2)维护卷积555
(子任务2的)正解?
我们可以考虑每个贡献的组合意义,大小为
a
i
a_i
ai 的连通分量贡献相当于在这个联通分量中选取一个点产生
K
K
K 的乘积贡献。
据此我们可以优化状态表示:
f
[
u
]
[
0
/
1
]
\mathrm{f}[u][0/1]
f[u][0/1] 表示
u
u
u 的子树中,当前连通分量是否已经做出贡献,这里为了方便转移,当前连通分量如果已经做出贡献就计入答案。
LL K, f[MN], g[MN];
void DFS(int u, int fz) {
f[u] = 1, g[u] = K;
for (int i = h[u]; i; i = nxt[i]) if (to[i] != fz) {
DFS(to[i], u);
g[u] = (f[u] * g[to[i]] + g[u] * f[to[i]] + g[u] * g[to[i]]) % Mod;
f[u] = (f[u] * f[to[i]] + f[u] * g[to[i]]) % Mod;
}
}
巧妙利用组合意义?O(n)。
当然老年选手可以这样:
那么我们考虑每一个dp数组对应的生成函数,我们把点u的生成函数记做
f u ( z ) = ∑ i d p ( u , i ) z i f_{u}(z)=\sum_{i}dp(u,i)z^{i} fu(z)=i∑dp(u,i)zi
那么我们合并u,v时的转移可以写成
f
u
(
z
)
=
f
u
(
z
)
(
k
f
v
′
(
1
)
+
f
v
(
z
)
)
f_{u}(z)=f_{u}(z)(kf_{v}'(1)+f_{v}(z))
fu(z)=fu(z)(kfv′(1)+fv(z))
而我们最后求的答案其实就是
k
f
1
′
(
1
)
kf_{1}'(1)
kf1′(1)
那么不妨设
g
u
=
k
f
u
′
(
1
)
g_{u}=kf_{u}'(1)
gu=kfu′(1)
那么我们考虑合并了一个子树的时候
g
u
g_{u}
gu 作何改变
f u ′ = ( f u g v + f u f v ) ′ f_{u}'=(f_{u}g_{v}+f_{u}f_{v})' fu′=(fugv+fufv)′
f
u
′
=
g
v
f
u
′
+
f
u
′
f
v
+
f
u
f
v
′
f'_{u}=g_{v}f_{u}'+f_{u}'f_{v}+f_{u}f_{v}'
fu′=gvfu′+fu′fv+fufv′
k
f
u
′
(
1
)
=
g
v
k
f
u
′
(
1
)
+
k
f
u
′
(
1
)
f
v
(
1
)
+
f
u
k
f
v
′
kf_{u}'(1)=g_{v}kf_{u}'(1)+kf_{u}'(1)f_{v}(1)+f_{u}kf_{v}'
kfu′(1)=gvkfu′(1)+kfu′(1)fv(1)+fukfv′
g
u
=
g
v
g
u
+
g
u
f
v
(
1
)
+
f
u
(
1
)
g
v
g_{u}=g_{v}g_{u}+g_{u}f_{v}(1)+f_{u}(1)g_{v}
gu=gvgu+gufv(1)+fu(1)gv
看起来这个式子十分的简单,如果我们设
t
u
=
f
u
(
1
)
t_{u}=f_{u}(1)
tu=fu(1)的话我们可以得到这样的两个式子
t
u
=
t
u
(
g
v
+
t
v
)
t_{u}=t_{u}(g_{v}+t_{v})
tu=tu(gv+tv)
g
u
=
g
u
g
v
+
g
u
t
v
+
t
u
g
v
g_{u}=g_{u}g_{v}+g_{u}t_{v}+t_{u}g_{v}
gu=gugv+gutv+tugv
如果您的生命已如风中残烛:
直接Ctrl+C Ctrl+V 多项式EXP模板即可。