专栏文章

题解:P14016 [ICPC 2024 Nanjing R] 拓扑

P14016题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minxwzo5
此快照首次捕获于
2025/12/02 10:09
3 个月前
此快照最后确认于
2025/12/02 10:09
3 个月前
查看原文
Hint
  • 定义:一棵有根树形成的任一排列 pp,若 iijj 的父亲,排列 pp 均满足 iijj 之前。更加形式化的,1i<jn\forall 1 \le i < j \le npjp_j 均不是 pip_i 的父亲。
  • 结论:设 fuf_u 表示以 uu 为根时该子树的合法拓扑序的数量,szusz_u 表示子树大小,则有 fu=szu!szvvsubtree(u)f_u = \dfrac{sz_u!}{\prod sz_v \mid v \in \rm{subtree}(u)}
以下是证明:
首先考虑二叉树的情况。若以 uu 为根,此时每颗子树内的相对顺序是确定的,只需要考虑子树间的相对顺序。故有:
fu=fv1×fv2×(szv1+szv2szv1)f_u = f_{v_1} \times f_{v_2} \times \binom {sz_{v_1} + sz_{v_2}}{sz_{v_1}}
若是三叉树,考虑将 v1v_1v2v_2 的相对顺序先固定形成一个整体后,再考虑 v3v_3,则可得:
fu=fv1×fv2×fv3×(szv1+szv2szv1)×(szv1+szv2+szv3szv1+szv2)=fv1×fv2×fv3×(szv1+szv2+szv3)!szv1!szv2!szv3!f_u = f_{v_1} \times f_{v_2} \times f_{v_3} \times \binom {sz_{v_1} + sz_{v_2}}{sz_{v_1}} \times \binom {sz_{v_1} + sz_{v_2} + sz_{v_3}}{sz_{v_1} + sz_{v_2}} \newline = f_{v_1} \times f_{v_2} \times f_{v_3} \times \dfrac{\left(sz_{v_1} + sz_{v_2} + sz_{v_3}\right)!}{sz_{v_1}!sz_{v_2}!sz_{v_3}!}
推广到一般,则可推出:
fu=(vson(u)fv)×(szu1)!vson(u)(szv!)=(szu1)!vson(u)(fvszv!)f_u = \left(\prod \limits_{v \in \rm{son}(u)} f_v\right)\times \dfrac{(sz_u - 1)!}{\prod \limits_{v \in \rm{son}(u)} (sz_v!)} \newline = (sz_u - 1)! \prod \limits_{v \in \rm{son}(u)} \left(\dfrac{f_v}{sz_v!}\right)
再由 (szu1)!=szu!szu(sz_u - 1)! = \frac{sz_u!}{sz_u} 做进一步的化简:
继续迭代可得:
fu=szu!vsubtree(u)szvf_u = \dfrac{sz_u!}{\prod \limits_{v \in \rm{subtree}(u)}sz_v}
dpi,jdp_{i,j} 表示节点 ii 位于第 jj 个位置的方案数。若 uuvv 的父亲,则当 dpu,idp_{u,i} 转移至 dpv,jdp_{v,j} 时,由于 uu 内存在其余子树,为了方便转移,方程中 dpi,jdp_{i,j} 不考虑子树 ii 内的顺序,在统计答案的时候再作更新。当 dpu,idp_{u,i} 转移至 dpv,jdp_{v,j} 时,需要考虑的就是 uu 的其余子树在整一拓扑序中的位置,以及 uu 的其余子树的相对拓扑序。 前者就是用组合数求出在剩余的位置中找 szuszv1sz_u - sz_v - 1 个将 uu 内不含 vv 子树内的节点放入的方案数,后者直接套结论(见上方 Hint)。故有:
dpv,j=i=1j1dpu,i×(niszvszuszv1)×(szuszv1)!wsubtree(u)wsubtree(v)szwdp_{v,j} = \sum \limits_{i = 1}^{j - 1} dp_{u,i} \times \binom{n - i - sz_v}{sz_u - sz_v - 1} \times \dfrac{(sz_u - sz_v - 1)!}{\prod \limits_{w \in \rm{subtree}(u) \land w \notin \rm{subtree}(v)} sz_w}
最后的答案便是:
dpi,i×(niszi1)×szi!vsubtree(i)szvdp_{i,i} \times \binom{n - i}{sz_i - 1} \times \dfrac{sz_i!}{\prod \limits_{v \in \rm{subtree}(i) }sz_v}
注意到转移方程可以前缀和优化,所以最后的时间复杂度是 O(n2)O(n^2)。千万需要先预处理出逆元,O(n2logn)O(n^2 \log n) 的做法在 CF 上会挂。放个核心代码吧:
CPP
void dfs1 (int u,int fa)
{
	sz[u] = prod[u] = 1;
	for (auto v : ve[u])
	{
		if (v == fa) continue;
		dfs1 (v,u);
		sz[u] += sz[v];
		prod[u] = 1ll * prod[u] * prod[v] % MOD;
	}
	prod[u] = 1ll * prod[u] * sz[u] % MOD;
}
void dfs2 (int u,int fa)
{
	for (auto v : ve[u])
	{
		if (v == fa) continue;
		int tmp = qpow (1ll * prod[u] * inv_prod[v] % MOD * inv_sz[u] % MOD,MOD - 2);
		for (int j = 1;j <= n;++j) ndp[j] = (1ll * dp[u][j] * calc (n - j - sz[v],sz[u] - sz[v] - 1) % MOD + ndp[j - 1]) % MOD;
		for (int j = 1;j <= n;++j) dp[v][j] = 1ll * ndp[j - 1] * f[sz[u] - sz[v] - 1] % MOD * tmp % MOD;
		dfs2 (v,u);
	}
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...