Live2D

Solution Set - “让季节停止哽咽”

0.「CTT 2017」「洛谷 P4004」Hello world!

  写答辩 \(\to\) 听 Para 赞美最短解 \(\to\) 冲到题解区看最短解 \(\to\) 叉掉最短解并赞美作者 \(\to\) 写答辩.

  这步长根号分治和修改次数均摊的味儿太明显了. 在步长大于 \(\sqrt n\) 时, 一切操作都能暴力. 在步长小于 \(\sqrt n\) 时, 我们需要快速找到路径上非 \(1\)\(a\) 值, 顺便维护同余步长的 \(a\) 和. 我们对步长 \(k<\sqrt n\) 单独建一棵树, 每个点的新爹是原来的 \(k\) 级爹, 然后找非 \(1\) 可以直接 DSU, 维护和就在 DFN 序列上分块维护差分以平衡复杂度. 最后可以做到 \(\mathcal O(n\sqrt n\log\log n+q\sqrt n)\), 可能还要加个 DSU 的复杂度. (

1.「CTT 2017」「洛谷 P4006」小 Y 和二叉树

  答案序列的第一个点显然是度数 \(<3\) 的编号最小的点, 记为 \(r\). 接下来考虑第二个点, 它可能是 \(r\) 右子树内的点或者 \(r\) 的父亲. 对于前者, 这是一个子问题, 直接用 (以 \(r\) 为根) 子树内度数 \(<3\) 的编号最小的点作为结果. 如果 \(r\) 一定要有右子树和父亲, 就用较小者当右子树.

  如果没有呢? 设 \(r\) 的邻接点为 \(x\), 我们需要决策 \(x\) 当爹还是当儿. 如果 \(x\) 子树内的满足条件的最小点仍 \(>x\), 显然当爹更优秀. 否则, 即使这一最小值 \(=x\), 此时 \(x\) 度数 \(\le2\), 让它当儿的决策空间包含当爹的决策空间, 其他情况直接形成优劣关系, 所以都应该让 \(x\) 当儿.

  最后, 预处理以 \(r\) 为根的子树最优点, 然后贪心搜一边就能求出结果. \(\mathcal O(n)\).

2.「CTT 2017」「洛谷 P4226」避难所

  其实答案已经写在样例里啦. 研究 \(6\times6\times6=3\times3\times3\times8\) 的一般情况: 设素数 \(x\) 是满足 \(x^3\le b\) 的最大素数, \(y\) 是满足 \(y^2>b\) 的最小素数, 那么 \(\overline{(xy)(xy)(xy)}\) 就会被贪心算法误判为 \(\overline{yyy(x^3)}\). 当然, 这里需要满足 \(x^2y>b\), 一个很 OI 的解决办法是小范围暴力或者打表 (枚举所有三位数判断), 因为这个问题只会在 \(b\) 足够小时发生. 暴力复杂度毛估 \(\mathcal O(b^4\log b)\) (所以建议打表), 大范围直接暴力扫素数可以做到 \(\mathcal O(b^{1/4}\log b)\), 挺快的 w.

3.「AGC 023F」01 on Tree

  那个… 这个 trick 是不是有什么名字呢? 树形拓扑限制, 贪心向爹合并就行. 一个序列整体可以记作 \((\text{one},\text{zero},\text{inv})\), 对它 exchange argument 即有贪心策略. \(\mathcal O(n\log n)\).

4.「AGC 024C」Sequence Growing Easy

  放过一道水题, 就会不想写更多不那么水的题的题解, 所以!

  填出值 \(k\) 的方案是唯一的: 放一个 \([0,1,2,\dots,k]\) 在它前面. 所以只有 \(a\) 值刚好和这个吻合的部分可以节约操作次数. 此外, 若 \(a_i>a_{i-1}+1\) 或者这样的序列会覆盖 \(0\) 位置, 就一定无解. \(\mathcal O(n)\).

5.「UR #1」「UOJ #21」缩进优化

  兔在以前的博客里鸣过警钟: \(a=kx+r\), \(x,k\) 可以同时枚举. \(\mathcal O(n+V\log V)\).

  为什么会做到 UR 的题?

6.「JOISC 2022」「LOJ #3694」一流团子师傅

  "二分答案" 的 tag 比较乱入, 实在是找不到合适的 tag 啦. 但这的确是一道很好的 learn to use binary search 的题.

  前三个子任务很好想: 我们不断尝试取出出现位置尽量靠前的一串🍡 (什么输入法糖), 每次在未用材料序列上二分出能够做🍡的最小右端点, 那么这个端点出的材料肯定要用, 反复二分 \(n\) 次就能取出一串🍡. 询问次数为 \(\mathcal O(mn\log(mn))\), 差一点点. 怎么只给这么点儿分???

  第四个子任务需要一点小小的 motivation: 我们刚才是依次为每串🍡找材料, 我们其实也可以尝试为每个材料找合适的🍡. 而一个材料可以放入🍡等价于不于🍡内已有材料重复, 也等价于放完之后, 用这串🍡以外的材料能做出 \(m-1\) 串🍡. 后一个判据是可用于二分的, 我们维护🍡集合, 对🍡集合二分找合适位置即可. 询问次数 \(\mathcal O(nm\log m)\), 赢.

7.「JOISC 2022」「LOJ #3695」鱼 2

  • Link & Submission.
  • 「A.数据结构-线段树」「C.性质/结论」

  和上个 solution set 里提到的思路本质类似, 我们更亲睐对静态的 "再吃不能" 的状态进行描述. 对于一条鱼 \(x\), 若存在 \(l<x<r\) 使得 \(\min\{a_l,a_r\}>\sum_{i=l+1}^{r-1}a_i\), 那么 \(x\) 就不可能打破 \([l,r]\) 的限制, 自然也就无法最终存活. 进一步的, \((l,r)\) 其实让 \(l+1\sim r-1\) 内的所有鱼都不可能存活. 我们称这样的 \((l,r)\) 为支配区间.

  若固定端点 \(l\) 分析 \(r\), 容易发现支配区间不超过 \(\mathcal O(n\log V)\) 个. 实际上支配区间显然要不包含要不相离, 所以 \(\mathcal O(n)\) 的上界也存在. 我们现在就把问题转化成了两个部分: 1) 动态维护支配区间. 2) 快速处理区间询问.

  对于 1), 套用固定端点分析的方式, 当 \(x\) 被修改时, 我们仅需要拿出所有与 \(x\) 有关 (支配 \(x\) 或者以 \(x\) 为端点) 的支配区间, 将它们的贡献删除, 修改 \(a\) 值后再重新加入, 最终就只会对 \(\mathcal O(\log V)\) 个支配区间的贡献进行修改. 那么, 如何快速取出这些区间呢? 对于以 \(x\) 为端点的区间, 我们可以进行 \(\mathcal O(\log V)\) 线段树二分大力枚举到 \(x\) 的区间和翻倍的最近位置, 检查这个位置是否与 \(x\) 构成支配区间. 对于支配 \(x\) 的区间, 显然仅会以刚才枚举过的端点位置作为左右端点, 且由于支配区间互不跨越, 总共 \(\mathcal O(\log^2V)\) 种可能的区间中也只有 \(\mathcal O(\log V)\) 个会有改动. 所以这里也可以大力枚举.

  对于 2), 设询问区间为 \([l,r]\), 为了仅使用 "是否被支配" 来描述一条鱼的存活性, 我们不妨令 \(a_{l-1}=a_{r+1}=+\infty\) (即, 直接在处理询问前做两次单点修改). 又由于一定至少有一条鱼能存活, 所以区间中被支配次数最小的鱼的数量就是答案. 简单线段树维护一下即可.

  最终复杂度是 \(\mathcal O(n\log^2V)\), 精细实现可以做到 \(\mathcal O(n\log n\log V)\), 兔写出来非常卡常, 喜提 LOJ 最劣解 😭.​

8.「JOISC 2022」「LOJ #3696」复兴计划

  属于是把 P/B/K 三个 MST 算法枚举了一边. (

  题目等价与多次询问原图以 \(|x-w|\) 为边权的 MST 边权和. MST 具有良好的可调整结构, 顺着这一点思考, 发现随着 \(x\) 的单调移动, 我们只会用 \(w\) 大的边替代 \(w\) 小的边, 而且按 \(w\) 升序尝试替代仍然优秀. 换句话说, 如果从 \(x=0\) 为初始状态向后调整, 每条边的替代目标是唯一的! 设我们用边权为 \(w_2\) 的边替代边权为 \(w_1\) 的边, 此时就要求 \(x\ge\lceil (w_1+w_2)/2\rceil\). 我们直接模拟求出所有替代, 按 \(\lceil (w_1+w_2)/2\rceil\) 排序, 和询问的 \(x\) 做双指针贪心替代边即可. 复杂度 \(\mathcal O(m\log m+nm+q)\), 当然找替代边可以用 LCT 等东西优化.

9.「UR #1」「UOJ #22」外星人

  1. 人是两两不同的.

  2. 外星人是.

  3. 外星人是两两不同的.

  4. 不要去重.

  5. 如果你一定要为外星人去重, 请 %$%^&去@人&)

  将 \(a\) 升序排列. 令 \(f(i,r)\) 表示仅考虑 \(a_{i..n}\) 时, 余数为 \(r\) 的方案数 (包含在 \(n\) 个空位中为这 \(n-i+1\) 个数选位置的方案). 转移是 \(\mathcal O(1)\) 的, 最终复杂度 \(\mathcal O(nV)\).

10.「CF 1286D」LCC

  "碰撞" 这个事件非常的局部, 我们反而没有办法直接处理, 所以可以考虑直接按时间升序枚举碰撞事件, 我们接下来就只需要能够钦定这个事件发生 / 不发生. 用 \(f(i,d)\) 表示考虑 \(1\sim i\), \(i\) 的方向为 \(d\) 且满足所有事件要求的概率, 依赖于其局部性, \(f(i)\) 仅仅是一个二维向量, 可以用数据结构维护一列线性变换. 钦定事件发生 / 不发生也可以通过修改转移矩阵实现. 复杂度 \(\mathcal O(2^3\cdot n\log n)\).

11.「CF 618G」Combining Slimes ⭐

  在数学家们苦苦寻求解析解的时候, 卑鄙的信息学家居然用数值解过题. (

  注意到格子的一段后缀被卡住时才会产生子问题, 这时这段最左端的数值得研究. 我们令 \(f(i,j)\) 表示在 \(i\) 个格子的游戏中 \(j\) 出现过的概率, 显然有 \(f(i,j)=f(i,j-1)\cdot f(i-1,j-1)\), \(f(1,1)=p\), \(f(1,2)=1-p\). 顺便, 我们可以表示出 \(j\) 恰好出现一次 (此时它必然留到最后) 的概率为 \(f'(i,j)=f(i,j)\cdot(1-f(i-1,j))\).

  接下来就能在刚才描述的子问题上 DP 了: 令 \(h(i,j)\) 表示在 \(i\) 个格子的游戏中, 最左端的格子最终为 \(j\) 时格子数值的期望总和. 那么

\[h(i,j)=j+\frac{\sum_{k<j}f'(i-1,k)h(i-1,k)}{\sum_{k<j}f'(i-1,k)}. \]

注意 \(j\) 的右侧必然 \(<j\), 除此之外无特殊限制, 所以正比于它们的出现概率求和就行.

  当然, 唯一的特殊情况是 \(j=1\), 此时要求 \(j\) 的右侧一开始 \(2\), 最终合并出任意的数. 看来我们还需要算一算和 \(f\) 类似, 但要求第一个数是 \(2\) 的状态 \(g(i,j)\), 有 \(g(i,j)=g(i,j-1)\cdot f(i-1,j-1)\), \(g(1,2)=1-p\); \(g'(i,j)=g(i,j)\cdot(1-g(i-1,j))\). 进而得到 \(j=1\) 时的结果:

\[h(i,1)=1+\frac{\sum_{k>1}g'(i-1,k)h(i-1,k)}{\sum_{k>1}g'(i-1,k)}. \]

  最终, 我们希望求出

\[\textit{ans}=\sum_{k\ge1}f(n,k)h(n,k). \]

  那你就要问了, 你这一堆没上界的求和让我怎么算呢?

  — 注意到所有东西关于 \(j\) 的收敛都很迅速, 所以人为限制 \(j\le L=50\) 即可保证精度.

  你还是不明白, 这 \(n=10^9\) 单次 \(\mathcal O(1)\) 也算不了啊?

  — \(f,g\) 关于 \(i\) 的收敛也… 所以只需要暴力算前 \(L\) 项, 后面的东西视作以 \(f'(L,\cdot)\) 或者 \(g'(L,\cdot)\) 为系数的常系数齐次线性递推, 矩阵快速幂什么的就能求出来了.

  复杂度 \(\mathcal O(L^3\log n)\), 不过带着关于精度要求的阈值算复杂度也没什么意思呢.

12.「QOJ #4219」Insects ⭐

  先想想固定黑白点集合的时候如何求答案. 问题等价于: 每个黑与右上方白点连边, 求该二分图的最大独立集. 先感知一下, 若一个白点在独立集中, 则其右上方的所有白点都在独立集中且所有黑点都不再独立集中. 因此, 最终入选的点一定能被一条从左上到右下的折线划分为两部分, 上半部分全部选白点, 下半部分全部选黑点. 我们只需要求出这条折线, 就得到答案了.

  最大独立集… 最大匹配… 我们可以发现这条折线是最小割! 我们先贪心地求出最大匹配: 按坐标降序枚举点, 枚举出黑点时向已出现的未被匹配的白点中, 高于黑点且尽可能低的白点连边, 正确性是容易证明的. 接下来, 我们构造一条不穿过匹配边的折线, 根据匹配边的贪心性质, 在不得不下降折线 (即将穿过匹配边) 时, 一定可以让折线竖直下降到匹配边的黑色端点而不穿过匹配边. 这样就能构造折线了.

  最后, 在不断加入白点时, 折线的每个位置都不会下降, 那么被折线划分开的部分点是能够永久确定会 / 不会被选择的. 我们只需要对询问整体二分, 每次决策还为确定的点即可. 复杂度 \(\mathcal O(n\log^2n)\).

  形式化的题解.

13.「CF 1188E」Problem from Red Panda

  不考虑可行性, 序列最终的值仅有每个位置的操作次数确定. 设操作序列为 \(\{x_n\}\), \(s=\sum_i x_i\), 那么最终有 \(a_i'=a_i+kx_i-s\), 这里要求 \(\min_i\{x_i\}=0\) 就能建立双射.

  接下来, 还需要描述 \(\{x_n\}\) 的可行性. \(a_i'=a_i+kx_i-s\ge0\Rightarrow x_i\ge\lceil (s-a_i)/k\rceil\), 同时 \(x_i\ge0\), 进而有 \(s=\sum_ix_i\ge\sum_i\max\{0,\lceil(s-a_i)/k\rceil\}\). 这里很巧妙, 虽然仅仅是必要条件, 但限制与 \(x\) 具体取值无关, 我们就可以方便地描述 "每个时刻都能进行下一步操作" 了! 因此, \(\{x_n\}\) 的合法条件为:

\[\forall t\in[0,s],~t\ge\sum_{i=1}^k\max\{0,\lceil(t-a_i)/k\rceil\}. \]

  最后, 枚举 \(s\), 用一些桶快速维护右式, 判断合法性后隔板出 \(\{x_n\}\) 即可求出方案数. 显然 \(s\le\max_i\{a_i\}\), 否则 \(\min_i\{x_i\}>0\). 故复杂度 \(\mathcal O(n+\max_i\{a_i\})\).

14.「CF 1023G」Pisces ⭐

  • Link & Submission.
  • 「A.数据结构-平衡树」「C.性质/结论」

  注意第一步转化: 建立 "一群鱼能到另一群鱼" 的偏序关系, 我们希望求出的就是带权最长反链. 即找到一组数量最多的鱼群集合, 使得两两鱼群不可在限定时间内到达.

  接下来需要用树的性质来简化讨论. 显然, 仅仅研究 \(r\) 子树的情况, "\(S\) 是反链" 等价于 \(S\) 在每棵 \(r\) 的孩子的子树内是反链, 且不存在能跨过 \(r\) 相互到达的鱼群. 那么我们可以得到一个简单的 DP: \(f(u,a,b)\) 表示 \(u\) 子树内到达 \(u\) 的最早时间是 \(a\), 允许 \(u\) 被子树外的鱼群到达的最早时间是 \(b\) 时, \(u\) 子树内的最大反链大小.

  优化一下? 转移的时候我们像是在对 \([b,a]\) 做区间交, 那么我们可以从一开始就值抽取区间内的点保存信息. 由于限制关系是 \(<\), 所以得取一些非整点, 当然所有时间 \(\times2\) 就可以只取整点了. 设新的状态为 \(f(u,t)\), 讨论其对父亲贡献时的情况, 设父边边权为 \(w\):

  • 若不选 \(u\) 中的鱼群, 那么 \(t\) 可以在 \([t-w,t+w]\) 里取最大值.
  • 如果选了 \(u\) 中的鱼群, 设为 \((d,f)\), 那么子树贡献是 \(f(u,d)\), 对父亲的贡献也是在 \([d-w+1,d+w-1]\) 内取最大值.

  接下来是维护工作, 用平衡树维护差分列, 这样取最大值操作就变为差分列的移动, 还需要用堆来抵消交错的正负差分位置. 最后叠加贡献就直接启发式合并差分列即可. 复杂度 \(\mathcal O(n+m\log^2m)\).

15.「UR #1」「UOJ #23」跳蚤国王下江南 ⭐

  • Link & Submission.
  • 「A.图论-圆方树」「A.数学-多项式」「A.树论-点分治/点分树」

  应该叫… 圆方树上有根点分治 FFT 板题. (?

  建圆方树嘛, 不过其实这里只关心从 \(1\) 到原点的信息, 所以并不需要建出方点, 直接把信息连在方点父亲上即可. 最终我们把问题转化成这样的形式: 给定一棵树, 每条边上的权值形如 \((x^a+x^b)\), 求根到所有点的权值乘积之和. 保证任意竖直路径的次数低于 \(n\).

  然后我们可以对这棵有根树进行点分治. 设希望求出 \(x\) 子树内所有点到 \(x\) 的信息, 有根树点分的基本思想大概是:.

  • 取出 \(x\) 子树的重心 \(r\), 并递归求解 \(r\) 的子树.
  • "序列分治" 求出 \(r\)\(x\) 的信息, 将它与从 \(r\) 子树内到 \(r\) 的信息合并, 贡献入答案.
  • 删除 \(r\) 子树, 再次递归 \(x\) 子树.

  不平凡的点是, "序列分治" 是不必要的, 我们可以先递归 \(x\) 子树, 此后 \(x\)\(r\) 的路径上会出现一列重心, 我们从 \(r\) 的父亲开始不断跳 "重心 \(\to\) 子树根" 一路跳上去, 利用已经求出的信息合并, 以此保证复杂度.

  这题写个 FFT 就好了. 跳重心的复杂度是 \(T(n)=\mathcal O(n\log n)+T(n/2)=\mathcal O(n\log n)\). 最终复杂度 \(\mathcal O(n\log^2n)\). 注意多项式运算 \(f\gets f+(x^a+x^b)g\) 的复杂度要求做到 \(\mathcal O(\deg g)\), 不然 T 成 joker.


  重庆的春 "哽咽" 了好几天, 气温暴跌二十多度, 差点冻死. (

posted @ 2023-04-26 20:48  Rainybunny  阅读(187)  评论(0编辑  收藏  举报