2025-07-11 总结
2025-07-11 总结
小R的旅行
Tag:点分治、倍增。
考虑从 \(u\) 走到 \(v\) 过程中,每条边的花费即此前 \(p_i\) 的最小值。那么对于链的情况,可以找到一个点往上或往下第一个 \(p_i\) 比它小的点,查询时用倍增跳即可。
现在考虑树,从 \(u\) 走到 LCA 依然可以类似链的做法,但从 LCA 走到 \(v\) 是不好做的。
考虑点分治,把询问挂在路径上的最浅重心上,那么我们可以预处理重心到子树内每个点的答案,然而不能直接合并。我们需要先知道从 \(u\) 到重心时 \(p_i\) 的最小值 \(Min\),然后根据这个最小值从 \(v\) 倍增跳到 \(x\),使得重心到 \(x\) 的花费大于 \(Min\),而 \(x,v\) 的花费不大于 \(Min\),从而算出答案。
考虑复杂度 \(T(n)=2T(n/2)+O(n\log n)=O(n\log ^2n)\)。
数数
Tag:组合数学、二项式反演、斯特林数。
首先假设 \(a_i\) 互不相同,在最后除以每种 \(a_i\) 出现次数的阶乘的乘积即可。
考虑计算划分成至少 \(k\) 个和为 0 的集合并排列的方案数 \(h_i\times i!\)。由二项式反演,那么答案为 \(ans_i=\sum _{j=i}^n(-1)^{j-i}\binom{j-1}{i-1}h_i\times i!\),这里因为最后一个集合的和一定为 \(0\) 所以系数为 \(\binom{i-1}{j-1}\)。
对于 \(cnt\) 个和为 \(s\) 的非 \(-1\) 数若划分进一个集合,方案数为 \((cnt+1)(cnt+2)\cdots(cnt+s)\)。若这 \(cnt\) 个数分别为 \(b_1,b_2,\dots,b_{cnt}\),那么考虑其组合意义,我们为每一个 \(i\) 任选一个 \(j\) 并令 \(c_i=b_j+[j\le i]\),则方案数为所有选 \(j\) 的方案中 \(\prod c_i\) 的和。
为一个 \(i\) 选 \(j\) 看做 \(i\) 向 \(j\) 连一条有向边,那么一个集合可能分成若干基环树。设 \(g_i\) 为将 \(n\) 个点分成 \(i\) 个基环树的方案数,其中一条边的贡献为 \(c_i\)。则 \(h_i=\sum _{j=i}^ng_i\times S_2(j,i)\),其中 \(S_2\) 为第二类斯特林数。
为了算 \(g_i\),考虑求出至少分成 \(i\) 个基环树的方案数 \(f_i\),那么由二项式反演 \(g_i=\sum_{j=i}^{n} (-1)^{j-i}\binom{j}{i}f_i\)。
算 \(f_i\),即确定 \(i\) 个环,剩下的点随便选,一个点随便选的方案数是 \(i+\sum a\)。
考虑一条环边 \((i,j)\),我们把贡献记作 \((b_j+1)-[j>i]\),那么它们相乘后的组合意义即,每个点 \(i\) 可以选择 \(a_i+1\) 的贡献或 \(-1\) 的贡献,其中 \(-1\) 的贡献只有当前一个点小于它时可以选。那么把环分割成若干链,其中链首的贡献为 \(a_i+1\),其余点的贡献为 \(-1\),并且要保证一条链上点编号递增。考虑求 \(dp_{i,j}\) 表示 \(i\) 个点分割成 \(j\) 条链的方案数。
那么对于一个点可以随便连,贡献为 \(i+\sum a\);可以作为链首,贡献为 \(a_i+1\);可以拼到一个链以后贡献为 \(-1\),并可以选择一个链拼,所以总贡献为 \(-j\)。
于是 \(dp_{i,j}=(i+\sum a)dp_{i-1,j}+(a_i+1)dp_{i-1,j-1}-j\times dp_{i-1,j}\)。
算出拼成 \(i\) 条链的方案数后,还要把 \(i\) 条链拼成环。则 \(f_i=\sum _{j=i}^ndp_{n,j}\times S_1(j,i)\),其中 \(S_1\) 为第一类斯特林数。
从后往前依次带入算式即可得出答案,复杂度 \(O(n^2)\)。
图排列
Tag:分治、偏序。
首先 \(n\) 个点的图是竞赛图,子图也是竞赛图。对于一个竞赛图,它的强连通分量会连成一个类似链的结构,其中链每对祖孙都有一条边,即构成一个全序关系。
现在考虑加入一个点,在从左往右的链上,如果找到最左被它连向的点 \(x\),和最右连向它的点 \(y\),那么 \(x,y\) 所在分量之间和它就会合并成一个强连通分量。我们可以预处理好所有点的 \(x,y\),然后维护这条链,使用链表将 \(x,y\) 分量之间的点缩起来,还需要维护一个并查集用于求出 \(x,y\) 所在的分量。
现在问题在于求出 \(x,y\)。考虑求 \(x\),\(y\) 是同理的。我们实现如下函数:
int Min(int x,int y) {
return (!x||!y)?(x|y):(x<y?(a[x]>b[y]?x:y):(a[y]>b[x]?y:x));
}
即 \(x\to y\) 当且仅当 \(Min(x,y)=x\)。
我们现在求出 \(p_i\) 的最左被它连向的点,发现对于 \(j<i,k<i\) 且 \(Min(p_i,p_j)=Min(p_i,p_k)=p_i\) 的 \(p_j,p_k\),若 \(Min(p_j,p_k)=p_j\),则 \(p_j\) 在 \(p_k\) 左边或与 \(p_k\) 在同一个连通块,\(p_j\) 更优。
所以对于 \(p_i\) 我们要求的点 \(p_j\) 有这几个条件:\(j<i\);\(Min(p_i,p_j)=p_i\);\(p_j\) 为满足以上两个条件的点集的 \(Min\)。
于是对 \(p_1,p_2,\dots,p_n\) 分治,每次用 \(p_{l}\sim p_{mid}\) 更新 \(p_{mid+1}\sim p_{r}\)。对于第二个条件可以讨论成二维偏序,对于第三个条件就是放在树状数组上求 \(Min\)。
复杂度 \(O(n\log ^2n)\)。

浙公网安备 33010602011771号