Solution Set - “愿所有罗盘都指向那片海洋”
- 0.「NOI Simu.」哈希计数 ⭐
- 1.「NOI Simu.」运输计划 ⭐
- 2.「NOI Simu.」时代的眼泪 ⭐
- 3.「Subset」LP 的被动练习 📓
- 4.「EC Final 2018」「LOJ #6632」Mysterious … Host ⭐
- 5.「洛谷 P5642」人造情感 ⭐
- 6.「洛谷 P9357」Lighthouse ⭐
- 7.「集训队作业 2021」「LOJ #3400」Storm ⭐
- 8.「Topic」TSP 与蚁群算法 📓
- 9.「SDOI 2019」「洛谷 P5359」染色 ⭐
- 10.「BZOJ #1283」序列 ⭐
- 11.「雅礼集训 2018」「LOJ #6511」B ⭐
- 12.「POJ #3689」Equations
- 13.「THUPC 2017」「洛谷 P7429」气氛
- 14.「洛谷 P6271」一个人的数论 ⭐
- 15.「UR #16」「UOJ #241」破坏发射台
好困, 等会儿还要默写单词.
别催嘛… 中间放了个端午 (整整一天假!) 所以慢了一点. 而且这次内容应该挺丰富的.
欸对啊, 那么对 ⭐, 几乎全是好题, 肯定会做久一点嘛!
预告一个「虚构往事」的大更, 虽然写着有点吃力就是了. (
0.「NOI Simu.」哈希计数 ⭐
- Private link & Submission.
- 「B.std::bitset」
比较脑经急转弯的状态优化. 我们很容易想到诸如 "\(F_s(z)\) 表示大小为 \(s\) 的树 hash 值的出现次数关于 hash 值的 GF", 但这个东西需要枚举子树转移, 就算是有根树在根处拼接也无法仅通过树的大小得到 hash 值增量, 我们也没有再引入其他维度的计算资源了, 怎么办呢?
我们只需要求一个 \(n\), 而并非所有 \(n\le n_0\)! 上面这个符合直觉的状态实际上是绊脚石. 已知树最终大小为 \(n\), 我们仅根据子树大小的确就能求出一条边被经过的次数! 我们定义 \(F_s(z)\) 表示已知树大小为 \(n\), 其一棵大小为 \(s\) 的子树内部边对 hash 值的贡献关于 … 的 GF, 那么
std::bitset
维护即可. 毛估 \(\mathcal O(n^6/\omega)\).
1.「NOI Simu.」运输计划 ⭐
你知道吗? 有一种处理高维偏序的技巧叫做高维前缀和.
不妨设 \(a_i\le b_i\). 设传送点设置在 \((L,R)\), 此时代价综合为
后面这东西分四种情况:
- \(a_i<L\le R<b_i\),
- \(a_i<L\le b_i\le R\),
- \(L\le a_i\le R<b_i\),
- \(L\le a_i\le b_i\le R\);
每种情况都可以用若干个二维前缀和维护答案 (觉得麻烦建议先写个暴力, 照着优化就行). \(\mathcal O(n^2+m)\).
2.「NOI Simu.」时代的眼泪 ⭐
- Private link & Submission.
- 「A.分块」
怎么编 motivation 呢? 直接讲算法吧.
对询问的 \(m_i\) 设定阈值 \(C\). 当 \(m_i\ge C\), 直接跑 \(\mathcal O(n\log n)\) 的二维偏序. 接下来处理 \(m_i<C\) 的情况.
对序列以 \(B\) 为块长分块, 预处理一个块到序列所有前缀产生的顺序对数量 (到块内的部分无意义, 但顺便处理也无妨), 在处理这个前缀和数组关于块编号的前缀和. 询问时, 用枚举每个询问区间的整块区间和其他询问区间贡献答案, 这样就只剩下散块到散块的贡献没有被算到, 直接把散块丢到上面的二维偏序再算一次就行.
设 \(m=\sum m_i\), 复杂度是 \(\mathcal O(m\log n/C+mB\log n+mC+n^2/B)\), 平衡出来大概就 \(\mathcal O(n\sqrt{n\log n})\) (\(n,m\) 同阶).
3.「Subset」LP 的被动练习 📓
LP 的变元默认 \(\in\mathbb N\), 虽然不强调 "整数 LP" 很不规范就是了. (
很经典很有推广意义的题, 兔的题解: link.
起手:
对偶:
打住! 到这里就是防守战线了 (没用这个方法写, 有问题踹一踹).
设 \(S_e\) 表示非树边 \(e\) 对应的树边集合, 题目所求即
似乎可以直接解. 我们还是更希望找到一个不那么粗暴的方法. 对偶:
虽然形式复杂了一点, 但这个变元的二分图关系就很明显了, 建图已经写在脸上, 上费用流就行.
事实上, 我们刚才完成的是从类似 KM 算法 (最小顶标和) 到二分图最大权多重匹配的转化.
不觉得上面那题强一点?
(还得遏制住直接来上下界流的冲动是吧?)
将所有点向 \(1\) 连一条边收集流量, 这次边构成集合 \(E_r\), 写一个网络流状的 LP:
这个 \(>0\) 看着太难受了, 令 \(f_{uv}'=f_{uv}-[\lang u,v\rang\in E\setminus E_r]\), \(d_u\) 为 \(u\) 的入度减去出度 (不计 \(E_r\)), 那么这个 LP 等价于
恭喜你! 你独立地发明了上下界网络流的建图方法!
4.「EC Final 2018」「LOJ #6632」Mysterious … Host ⭐
- Link & Submission.
- 「A.数学-生成函数」「A.数学-多项式」
我们需要计数叶子数量为 \(n\) 的析合树, 树的形态或树点类型 (叶子, 析点, 合点) 不同则视为不同的树. 分别选用叶子, 析点, 合点为子树根, 可以得到 GF:
这是因为析点一定有至少四个儿子 (i.e. 有至少四个儿子, 我们就能把值域拆成满足析点性质的段), 合点至少有两个儿子 (i.e. 有至少两个儿子, 我们就能把值域拆成满足合点性质的段). 满足这两个性质, 我们就能根据析合树构造出至少一个排列. \((1-F(z))^{-1}=\left.(1-z)^{-1}\right|_{F(z)}\) 即挂上更多儿子.
到此, 我们需要解方程:
牛迭得到:
啊… 这式子有够麻烦的, 总之可以 \(\mathcal O(n\log n)\) 多项式算出来.
5.「洛谷 P5642」人造情感 ⭐
- Link & Submission.
- 「A.DP-树上 DP」
纯 DP 题? 还是有什么高深的背景呢?
题目中, \((u,v)\) 对答案的贡献即 "全局最大权值和 \(-\) 禁用 \(u\to v\) 上的结点后能选出的最大权值和". 先考虑前半部分, 尝试 DP, 令 \(f(u)\) 表示仅考虑完全在 \(u\) 子树内的路径时, 能选出的最大权值和, \(f'(u)\) 表示额外禁用点 \(u\) 时的上述答案, 显然 \(f'(u)=\sum_{v\in\son(u)}f(v)\). 考虑 \(f(u)\):
-
若没有路径过 \(u\), 有
\[f(u)\chkmax f'(u). \] -
若有路径经过 \(u\), 则 \(u\) 是该路径端点的 LCA. 枚举这样的路径 \(P=(x,y,w)\), 有
\[f(u)\chkmax f'(u)+w-\sum_{v\in(x\to y)}(f(v)-f'(v)). \]
后面的求和可以用 BIT 在 DFN 上维护, 所以我们可以 \(\mathcal O(n+m\log n)\) 求出 \(f\).
如何求答案呢? 可以看出, 当固定的 \(u\to v\) 被禁用时, 我们可以用多个 \(f\) 和一个 "子树外答案" 相加得到. 加法可以拆贡献, 那么求出 "子树外答案" 差不多就结束了. 令 \(g(u)\) 表示仅考虑 \(u\) 子树外 (不包括 \(u\)) 的路径时, 能选出的最大权值和, 设 \(v\in\son(u)\), 那么:
-
若没有路径经过 \(u\), 有
\[g(v)\chkmax g(u). \] -
若有路径 \(P=(x,y,w)\) 经过 \(u\), 设该路径 LCA 为 \(h\), 有
\[g(v)\chkmax g(h)+w(P)-f(v), \]其中
\[w(P)=f'(u)+w-\sum_{v\in(x\to y)}(f(v)-f'(v)), \]也就是刚才我们求出 \(P\) 的转移贡献.
第一种情况很好转移. 对于第二种情况, 若 \(h=u\), 按 \(w(P)\) 排序后暴力扫出第一条可以转移的路径就行. 若 \(h\neq u\), 则 \(P\) 的 LCA 是 \(u\) 的祖先, \(P\) 的某个儿子在 \(\subt(u)\setminus\subt(v)\) 内. 按照前一个条件的 DFS 顺序, 在 DFN 上的线段树维护第二个条件就行. 也是 \(\mathcal O(n+m\log n)\).
最后, 枚举 \(u\), 考虑 \(f(u)\) 和 \(g(u)\) 对答案的贡献次数即可. 复杂度 \(\mathcal O(n+m\log n)\).
6.「洛谷 P9357」Lighthouse ⭐
- Link & Submission.
- 「A.数学-组合计数」
"\(u\) 所在连通块大小" 听着就吓人, 我们可以拆成 "能够走到 \(u\) 的结点数量", 然后对这样的有序点对 \((u,v)\) 计数. 不难发现, \(v\to u\) 的总贡献仅和 \(|v\to u|\) 有关. 设有 \(c_k\) 条包含 \(k\) 个结点的路径, 枚举这条路径上的点权全部相等时的值, 可以得到
不会了, 顶多硬上多项式.
数学变换毁天灭地, 组合意义曲线救国. 我们枚举 \(\ell\) 的目的是限定 "当 \(v\to u\) 中的所有点都达到某值时, \(u\) 在 \(\ell\) 时刻首先被 \(+1\)". 这个枚举听上去不太妙, 它同时引入了 \(n-k\) 的幂和 \(n\) 的幂, 非常麻烦. 我们直接枚举一共有多少次操作涉及到 \(v\to u\) 中点, 设 \(f(k,x)\) 表示长度为 \(k\) 的路径被操作 \(x\) 次时, 内部对答案的贡献总和, 那么
这个循环勉强能跑吧, 看看 \(f(k,\cdot)\)?
赢! 递推 \(f\), 然后求答案. \(\mathcal O(nm+m\log n)\). 但这搬题人卡常咱也没办法.
7.「集训队作业 2021」「LOJ #3400」Storm ⭐
- Link & Submission.
- 「A.随机化」「A.图论-网络流`-费用流」
Key motivation: 给数据范围 \(\sum 2^k(n+m)\le10^6\) 编个理由.
关于 \(k\) 的指数级算法? 有点科幻, 毕竟整整 \(m\) 条边可选. 也许可以网络流, 那这是拿来保证网络流复杂度? 但也不可能建出一个指数级的流网络吧.
也许, 是保证随机算法正确率? — 甚至我们都能猜出随机方法: 每个点 (边) 随机在某个二元集合中选一个?
原问题很像网络流, 但简单分析可知根本不可能建图. 我们先来分析一下最优选择的性质, 显然, 若仅仅考虑被选择的边, 图将变成一个菊圃 (i.e. 菊花构成的森林, 这些名词太好玩儿了). 等等! 如果我们获得神谕, 把所有花心放入 \(X\) 集合, 把所有花瓣放入 \(Y\) 集合, 仅考虑 \(X,Y\) 之间的边, 就能通过费用流求出最优答案了!
结合刚刚的猜测, 答案已经明了: 每个点随机扔到 \(X\) 或者 \(Y\), 划分出二分图, 仅考虑两集合中间的边, 跑费用流.
假设只有一种最优方案, 那么这种方案在一次随机中被猜中的概率至少是 \(2/2^k\) (仅一朵菊花, 概率最低).
Lemma. 连续抛掷 \(-\frac{\ln\epsilon}{p}\) 次一枚以 \(p\) 的概率正面朝上的硬币, 出现至少一次正面朝上的概率至少为 \(1-\epsilon\).
Proof. 不存在正面朝上的概率: \((1-p)^{-\frac{\ln\epsilon}{p}}=((1-p)^{1/p})^{-\ln\epsilon}\le(1/e)^{-\ln\epsilon}=\epsilon\).
因此, 进行上述随机过程 \(-2^k\ln\epsilon\) 次就能得到 \(1-\epsilon\) 的正确率. 最终复杂度 (假设费用流用未特殊化的势能 Dijkstra) \(\mathcal O(2^kk(n+m)\log(n+m)\cdot-\log\epsilon)\).
8.「Topic」TSP 与蚁群算法 📓
-
「C.非传统-提答题」「Y.算法总结」
你家 NOI 模拟赛给兔整这个?
参考资料, 讲得挺好, 这里就只简单记一下算法流程:
- 迭代:
- 在图上随机放置 \(m\) 只蚂蚁.
- 模拟每只蚂蚁的行动: 设蚂蚁在 \(u\), \(u\) 邻接的未访问集合为 \(A_u\), 正比于 \(\tau_{uv}^\alpha/w_{uv}^\beta\) 在 \(A_u\) 中选择转移点 \(v\). 其中 \(\tau\) 为信息素浓度矩阵, \(w\) 为距离矩阵 (本质上是根据最小化目标选取对应函数, 这里是 \(y=1/x\)). \(\alpha,\beta\) 表示二者权重.
- 模拟信息素挥发: \(\tau\gets(1-\rho)\tau\), \(\rho\) 即挥发因子.
- 模拟信息素散布: 对每只蚂蚁求出其最终路径长度 \(d\), 在其经过的边上加上 \(Q/d\) 的信息素. \(Q\) 为信息素常数.
- 更新答案: 用每只蚂蚁的 \(d\) 更新最优答案.
这个搜索出解的质量还是挺高的, 本题共 \(14\) 个搜索点, 兔的 generator 共计 \(8.5\) 核时搜出的解, 每个都至少比标算答案优秀 \(10^8\).
9.「SDOI 2019」「洛谷 P5359」染色 ⭐
- Link & Submission.
- 「A.DP-计数 DP」「C.思维」
crashed:“我看到过这道题。”
crashed:“我当时以为,怎么有这么简单的省选题,就把它跳了。”
crashed:“我考试的时候越想越发现,这道题不是那么简单。”
在子任务的提示下, 我们可以尝试研究这样一个问题: 若一段连续空白的左端两个和右端两个都已给出, 如何计算中间的方案数. 经过不懈努力, 可以讨论出五个状态:
进而给出 DP, 令 \(f(\ell,s)\) 表示一段长度为 \(\ell-1\) 的空白, 空白左右情况为 \(s\) 时, 内部染色方案数. 转移也需要不懈讨论. 这里就给个结果:
static const int TRS[5][5] = {
{ 0, 1, 0, 2 * (c - 2), mul(c - 2, c - 3) },
{ 1, 0, 2 * (c - 2), 0, mul(c - 2, c - 3) },
{ 0, 1, c - 2, 2 * c - 5, mul(c - 3, c - 3) },
{ 1, 0, 2 * c - 5, c - 2, mul(c - 3, c - 3) },
{ 1, 1, 2 * (c - 3), 2 * (c - 3), add(c - 3, mul(c - 4, c - 4)) }
};
// addeq(f[i][j], mul(TRS[j][k], f[i - 1][k]));
利用 \(f\), 我们可以在两个相邻的非空白列间快速转移. 因为非空列限定了至少一个位置的颜色, 记录另一个颜色就不那么困难了. 令 \(g(i,c)\) 表示处理到地 \(i\) 个非空列, 空白位置颜色为 \(c\) 时的方案数. 对 \(g(i,\cdot)\) 上的变换是全局加, 全局乘, 单点赋值, 全局清零 (可以均摊实现, 规避\({}\times0\)), 单点查询, 全局求和. 可以用一个数列加上全局 \(kx+b\) 标记快速维护. 赋值需要求 \(k\) 的逆元, 但格子总长度只有 \(n\), 故仅有 \(\mathcal O(\sqrt n)\) 种转移系数, 求逆元的时候记忆化一下就可以规避 \(\log\). 最终复杂度 \(\mathcal O(n)\).
10.「BZOJ #1283」序列 ⭐
- Private link & Submission.
- 「A.数学-线性规划」「A.图论-网络流-费用流」
还是线规, 我忍一下. 这里的作业题应该比起上面的 subset 会不平凡一点, 就拆开写了.
看了眼题解, 大概是转化成:
约束条件中的等式相邻作差, 就有 \(x_t-x_{t+m}=y_{t+1}-y_t\), 即 \(x_t+y_t=x_{t+m}+y_{t+1}\), 再加上 \(k=\sum_{i=1}^mx_i+y_1\) 和 \(\sum_{i=n-m+1}^nx_i+y_{n-m+1}=k\) 这两个等式, 所有变量恰好在等号左右各出现一次, 转化为流量守恒跑费用流就行, \(\mathcal O(\text{Dinic}(3n,4n))\).
的确很巧妙, 但感觉不是很自然啊.
11.「雅礼集训 2018」「LOJ #6511」B ⭐
- Link & Submission.
- 「A.数学-线性规划」「A.图论-网络流-费用流」
二分答案 \(T\), 得到线规:
(啊? 怎么听说又可以直接单纯形啊?) 对偶:
相信你已经看出来些东西了. 这个 LP 描述的是 DAG 上路径覆盖: 每次花费 \(T\) 买一条路径拿来覆盖, 点 \(u\) 前 \(c_u\) 次被覆盖, 每次带来 \(t_u\) 的收益, 此后 \(u\) 仍然能够被覆盖但不能带来收益. 费用流即可. \(\mathcal O\left(\text{Dinic}(2n,4n+m)\log\sum t_u\right)\). 当然, 图是一定的, \(T\) 的代价加不加都不影响增广流的凸性. 我们可以在增广途中用当前流量和费用计算答案. 这样就去掉了 \(\log\).
12.「POJ #3689」Equations
- Private link | 计算几何, 再见!
- 「A.数学-线性规划」「A.计算几何」
要求解:
注意 \(x_i\) 为非负实数, \(a_i,b_i,c_i\) 皆非负, 所以约束中的 \(=\) 可以改写为 \(\le\). 借此对偶得到:
约束形如 \(ax+by+c\ge0\), 半平面交出一个约束 \((p,q)\) 范围的凸包, 此后的询问就是求凸包内的点与给定向量的点积最大值, 根据几何意义可以简单双指针完成. 别忘了我们在做 \(\le\) 的问题, 还需要判断能否取 \(=\). 如果 \((s,t)\) 对应的射线与凸包无交就无解. \(\mathcal O(n+m)\) (输入都是小范围整数就假装没有排序的 \(\log\) 吧).
13.「THUPC 2017」「洛谷 P7429」气氛
- Link & Submission.
- 「A.数学-线性代数」
不会啊, 咋没人写证明啊.
\(n-1\) 维空间内 \(n-1\) 个向量张成平行多面体的体积为行列式绝对值.
\(n-1\) 维空间内锥体体积为对应平行多面体体积的 \(1/(n-1)!\).
\(n-1\) 维空间内 \(n+1\) 个顶点的凸包体积为 \(\binom{n+1}{n}\) 个小凸包体积和的一半.
拿着结论算就行, \(\mathcal O(Tn^4)\).
14.「洛谷 P6271」一个人的数论 ⭐
- Link & Submission.
- 「A.数学-数论」
直接来.
我们知道前 \(n\) 个自然数幂和可以写成 \(g(x)=\sum_{i=0}^{k+1}g_ix^i\), 代入:
研究中间的卷积, 设 \(h=\mu\star\text{id}^{i-k}\), 则:
提取它的单项系数是容易的. 非常粗糙地实现可以做到 \(\mathcal O(k^3+km\log P)\), \(P\) 是模数.
15.「UR #16」「UOJ #241」破坏发射台
- Link & Submission.
现在看到 "相邻颜色不同" 这句话就 PTSD.
\(2\nmid n\) 是经典容斥练习, 答案为 \((m-1)^n+(-1)^n(m-1)\).
\(2\mid n\) 时, 直接计算答案有点困难, 还是回到基础的矩阵快速幂. 钦定两个相对位置的颜色为 \(A,B\) 破环, 每次顺时针转圈同步选择相对的两个颜色, 维护 \(7\) 种状态, 手打一个 \(7\times7\) 的转移表即可, \(7^3\times\mathcal O(\log n)\).