Solution Set - “谁将重力悬空,坠入一场蔚蓝的梦”
- 0.「NOI Simu.」皮配 ⭐
- 1.「BZOJ #4671」异或图
- 2.「CF 1158F」Density of subarrays
- 3.「CF 794G」Replace All ⭐
- 4.「UR #15」「UOJ #225」奥林匹克五子棋
- 5.「NOI Simu.」么西 ⭐
- 6.「UR #14」「UOJ #193」人类补完计划 ⭐
- 7.「NOI Simu.」伊莉斯
- 8.「集训队互测 2021」「LOJ #3634」音符大师 ⭐
- 9.「NOI Simu.」城市贸易
- 10.「ARC 162A」Ekiden Race
- 11.「ARC 162B」Insertion Sort 2
- 12.「ARC 162C」Mex Game on Tree
- 13.「ARC 162D」Smallest Vertices ⭐
- 14.「ARC 162E」Strange Constraints
- 15.「ARC 162F」Montage ⭐
0.「NOI Simu.」皮配 ⭐
- Private link & Submission.
- 「A.图论-网络流-费用流」「B.贪心」
让兔先假定你心中有一个 \(3\) 层 \(n+m+w~(w=\log V)\) 个点, \(\mathcal O(nw)\) 条边的费用流模型.
从模拟费用流的角度出发, 我们可以采用增量-最大费用任意流. 从大到小加入代表公共 bit 的 \(w\) 个虚点, 注意到增量过程中只有源汇路径可能为正环, 不可能存在其他正环, 也就是说已经加入的虚点不会因后续增广退流.
但是这个流网络毕竟描述的是一般二分图匹配, 我们没办法找到可行的反悔贪心策略, 那就直接检查合法性吧! 根据不退流结论, 我们可以从高到低确定每个虚点的流量, 二分之, 然后对 \(w\) 个虚点做 Hall 定理的检查. \(\mathcal O(V\log V)\) 预处理 \(A,B\) 的子集和 (FWT-AND) 后可以 \(\mathcal O(1)\) 检查单个判据, 最终复杂度是 \(\sum_{i=0}^{w-1}2^{w-i}\log n+V\log V=\mathcal O(V(\log n+\log V))\).
1.「BZOJ #4671」异或图
- Private link & Submission. (懒得登 dark 的号了, 需要看题就自己找找叭.)
相比于 "连通", "不连通" 明显要更方便限制一些. 我们枚举 \(V\) 的连通块划分情况, 求出 "至少包含 \(k\) 个连通块" 的方案数, 最后二项式反演一发就能得到答案. 对于确定的连通块划分, 我们需要钦定连通块之间的所有边不存在, 对一条边的限制相当于要求 \(x_i=[G_i\text{ is chosen}]\) 的一个线性组合得到 \(0\), 所以方案数就是 \(m-{}\)限制矩阵的秩. 复杂度 \(\mathcal O(\text{part}(n)n^2m)\).
2.「CF 1158F」Density of subarrays
- Link & Submission.
- 「A.DP-计数 DP」
令原题中 \(c\) 为 \(m\). 先看看如何检查一个确定序列的密度是否 \(\ge p\). 我们可以构造一个最 "不容易" 出现在序列中的子序列: 每次找到所有数的下一次出现位置中最远的一个, 看能否完成 \(p\) 次迭代. 这个判断等价于将序列划分为 \(p\) 段, 使得每段中 \([1,m]\) 中的数都出现至少一次.
设 \(g(i,j)\) 表示 \([i,j]\) 中可以选出多少个包含 \(j\) 的, 密度为 \(1\) 的子序列, 由于强制包含 \(a_j\), 所以这相当于 \(a_j\) 的其他出现位置不能选, 其他值的出现位置随便选非空子集. 设 \(f(i,j)\) 表示 \([1,i]\) 中可以选出多少个包含 \(i\) 的, 密度为 \(j\) 的子序列, 则
答案即 \(\sum_if(i,j)2^{n-i}\) 对 \(j\) 差分的序列. 复杂度 \(\mathcal O(n^3/m)\). 你要说这能过? 特判 \(m=1\), 然后保证瓶颈 cache-friendly 就过啦!
3.「CF 794G」Replace All ⭐
- Link & Submission.
- 「C.性质/结论」
先不考虑 \(\str ?\), 对于已知串 \((A,B)\), 尝试计数合法的 \((S,T)\) 数量.
若 \(A=B\), 显然答案是 \((2^{n+1}-2)^2\). 否则, 考察两串前缀第一个互异的位置, 可以发现 \(S,T\) 存在 border 关系. 又因为最终的串相等, 所以 \(S,T\) 一定是由各自长度为 \(d=\gcd(|S|,|T|)\) 的 period 重复生成的. 设 \(A\) 中的 \(\str A\) 比 \(B\) 中的 \(\str A\) 多 \(a\ge 0\) 个, \(B\) 中的 \(\str B\) 比 \(A\) 中的 \(\str B\) 多 \(b\ge 0\) 个, 讨论一下:
若 \(a=b=0\), 则任意满足周期限制的 \((S,T)\) 都可行. 方案数为
否则有 \(a,b>0\), 且满足 \(a|T|=b|S|\). 先 \(a,b\) 约分得到 \(a',b'\), 现在就有 \(d\le n/\max\{a,b\}\). 方案数为
OK, 引入 \(\str ?\), 设 \(A\) 中有 \(a_1\) 个 \(\str A\), \(c_1\) 个 \(\str ?\); \(B\) 中同理有 \(a_2,c_2\), 那么
这样就 \(\mathcal O(n)\) 结束了. 注意 \(2\) 的幂需要预处理到 \(n+1\), 还要注意 \(\str ?\) 替换完之后可能出现的 \(A=B\) 的情况.
4.「UR #15」「UOJ #225」奥林匹克五子棋
- Link & Submission.
想歪了, 卡半天. \(k=1\) 无解, \(k=2\) 要求 \(n=1\) 或者 \(m=1\). 对于 \(k\ge3\), 给出构造:
OXOXO
XOXOX
XOXOX
OXOXO
若行列从 \(1\) 开始标号, 按照 \([i\bmod 4<2]\oplus[2\nmid j]\) 分为黑白双方即可. \(\mathcal O(nm)\).
5.「NOI Simu.」么西 ⭐
- Private link & Submission.
- 「A.DP-数据结构优化 DP」「A.数据结构-李超树」
挺巧妙的维护技巧. 令原题中 \(k\) 为 \(m\). 设 \(f(i)\) 表示你觉得它该表示的东西, 那么
转移可以表示为 \(\mex\{\}\cdot s_i+g(j)\) 的形式, 其中 \(\mex\{\}\) 值域小但在变化, \(s_i\) 固定不变但值域很大, 我们接下来需要找到一个可以扬长避短的算法.
首先, 当扫描 \(i\) 时, 左端点 \(j\) 对应的 \(\mex\) 值总共只有 \(\mathcal O(n)\) 次区间变化. 我们用一棵线段树套李超树维护 \(\ell_i\colon y=-s_ix+f(i)\), 支持区间查询函数最大值, 这样我们就能实时得知 \(\mex=k\) 时, 最优秀的转移点. 对于 \(k=1,2\cdots,n+1\) 的最优秀的转移点, 它们又能写成 \(\ell_k'\colon y_k=ks_k+c_k\), 其中 \(c_k\) 即在树套树上查询到的区间最值. 由于斜率很小, 我们对斜率分块维护凸包 (单点修改暴力重构块, 查询时单调扫描凸包) 就能完成最后转移.
加上 \(m\) 的限制也没问题, 每次挑出 \(i-m-1\) 对应的 \(\mex=k\), 将 \(k\) 的最优转移点重新算出来插回凸包即可. 复杂度 \(\mathcal O(n\sqrt n)\).
呃… 维护 \(\ell_k'\) 的部分应该可以换成另一棵线段树套李超树, 这样可以有 \(\mathcal O(n\log^2n)\) 的算法.
6.「UR #14」「UOJ #193」人类补完计划 ⭐
- Link & Submission.
- 「A.DP-状压/插头 DP」「A.数学-容斥计数」
其实跟着直觉走是有前途的, 不过需要一定的容斥技巧.
需要数基环树的权值和? 先数简单环环! 钦定每个环从最小标号点处开始绕圈, \(f(S,u)\) 表示经过了 \(S\) 内的点最终到达 \(u\) 的方案数, \(\mathcal O(n^22^n)\) 可以求出 \(g(S)\), 描述点集为 \(S\) 的简单环数量.
然后数基环树! 这里就比较 tricky 了, 对于 \(g(S)\), 我们枚举 \(T\cap S=\varnothing\), 将 \(T\) 中的结点作为叶子构成点集为 \(S\cup T\) 的一棵基环树, 贡献向 \(g(S\cup T)\). 但是这样会算重, 我们可以认定一棵基环树的理想的扩展顺序是每个叶子能加入点集时就加入, 这样 \(T\) 会带上 \((-1)^{|T|+1}\) 的容斥系数. 将 \(T\) 作为 \(S\) 的叶子的方案数可以现场对 \(T\) 递推, 这部分的复杂度是 \(\mathcal O(3^n)\).
最后数权值和! 仍然对 \(S\) 枚举 \(T\cap S=\varnothing\), 类似二项式反演, 将上面的转移系数完成 \(2^{|S|}(-1)^{|T|}\) 贡献向答案即可. 这里也是 \(\mathcal O(3^n)\), 就结束了.
7.「NOI Simu.」伊莉斯
先考虑只有一个魔眼在 \((x_0,y_0)\) 时, 我们从 \((x,y)\) 走到 \((n,n)\) 需要的最小代价. 不难发现贪心策略是优先在坐标值小于魔眼的维度上移动, 这样每次移动都会让距离减小, 然后再任意移动, 距离一定连续增大. 会算自然数前缀和, 我们可以 \(\mathcal O(1)\) 计算出这个最小代价.
然后是猜猜部分, 我们猜测对行动产生最强限制效果的是魔眼矩形的四个角落, 每次先尝试移动 R
再尝试移动 U
, 对这四个角落的魔眼做上述检查即可判断合法性 (最优策略是一样的, 所以检查是独立的), 这样就 \(\mathcal O(n)\) 结束了.
绷: 可是检查并不独立, 左上和右下的魔眼的最优策略并不相融. 而最小化左上魔眼和最小化右下魔眼的路径之间, 可以通过不断让一个代价 \(-2\), 另一个代价 \(+2\) 连续变化得到, 需要进一步判断.
8.「集训队互测 2021」「LOJ #3634」音符大师 ⭐
- Link & Submission.
- 「A.DP-数据结构优化 DP」「C.性质/结论」
不妨设 \(p_0=0\) 用以描述初始位置. 显然, 存在某种最优策略, 两只手的位置永远在集合 \(\{p_i\}\cup\{p_i-L\}\) 之中. 那么一个最压缩的状态形式就是 \(f(i,j,x,y)\) 表示处理到 \(p_i\), 一只手在 \(p_i-xL\) 处, 另一只手在 \(p_j-yL\) 处时的最小代价.
转移, 看上去就很 DS 的样子. 我们将 \(j,y\) 两个维度丢到线段树上. 转移时, 找到最近的不被 \(p_i-xL\) 覆盖的点 \(p_k\), 线段树上覆盖 \(p_k\) 这个位置的 \(p_j-yL\) 最多 \(\mathcal O(L)\) 个, 我们可以暴力转移. 其余情况, 我们需要讨论是 \(p_i-xL\) 走过去覆盖 \(p_k\) 还是树上的某个区间去覆盖 \(p_k\), 但 "走过去覆盖" 一定会停留在 \(p_k-L\) 或者 \(p_k\), 线段树维护前后缀最小值, 先做 "\(p_i-xL\) 走过去" (继承线段树, 全局加法), 再做其他转移 (单点修改) 即可. 时间和空间都是 \(\mathcal O(nL\log n)\) 的.
"兔 (bunny) 崽子, 那你写了个啥?"
处理完 \(p_{1..i}\) 时, 游戏局面可以记录为 \((x,y,s)\), 表示一只手在 \(x\), 另一只手在 \(y~(x\le y)\), 代价为 \(s\).
显然, 如果存在 \((x_1,y_1,s_1)\) 和 \((x_2,y_2,s_2)\), 使得 \(s_1+|x_1-x_2|+|y_1-y_2|\le s_2\), 这样的 \((x_2,y_2,s_2)\) 就一定不会优于 \((x_1,y_1,s_1)\), 称其被支配. 我们记录所有不被支配的状态的集合 \(\{(x,y,s)\}\), 加入 \(p_{i+1}\) 时暴力更新所有状态: 若 \((x,y,s)\) 本来就能覆盖 \(p_{i+1}\), 保持不动; 否则扩展出 \(x\) 去覆盖 \(p_{i+1}\) 和 \(y\) 去覆盖 \(p_{i+1}\) 两种状态. 最后, 暴力枚举新状态集合中的一对状态, 删掉所有被支配的状态.
就这样, 过了, 跑得那叫一个一骑绝尘, 比标算快六倍. 这玩意儿到底什么复杂度呢?
9.「NOI Simu.」城市贸易
宇宙无敌究极打火机题, 点分治 FFT 求出路径长度 GF, 多点求值求答案. \(\mathcal O(n\log^2n)\).
10.「ARC 162A」Ekiden Race
- Link & Submission.
\(i\) 能获得 fastest return award 当且仅当 \(\forall j>i,~p_j>p_i\). \(\mathcal O(n)\)
11.「ARC 162B」Insertion Sort 2
- Link & Submission.
一次操作对逆序对带来的变化量是偶数, 因此初始逆序对数为奇数就无解. 否则, 考虑每次将最小的错位的值归位. 如果这个最小值的位置不是 \(n\), 一步操作搞定; 否则此时 \(n-2,n-1,n\) 一定都没有被处理到, 先操作一步把最小值换到 \(n-2\) 这个位置上再一步归位即可. 随便写 \(\mathcal O(n^2)\).
12.「ARC 162C」Mex Game on Tree
- Link & Submission.
对于 \(u\) 子树, 若子树内没有出现过 \(k\), Alice 才可能让 \(f(u)=k\). 当然, 这也意味着 Bob 每次修改都会将某个 \(a_x\) 改成 \(k\), 这样 \(x\) 所有祖先对应的子树都不可能产生 Alice 的获胜状态. 因此, 当且仅当存在某棵子树 \(u\), 其不包含 \(k\), 包含 \(c\le1\) 个 \(a=-1\), 且 \([0,k)\) 内的数至多 \(c\) 个没出现时, Alice 才可以通过这棵子树获胜. 否则 Alice 不管怎么修改, Bob 都可以立马把她的修改可以影响到的子树全部扬掉, Alice 就必败了. 反正搜一遍子树就行, 复杂度取决于维护方式.
看看你需要多久找到这份提交的 bug, 一眼看出来奖励你一只烤兔兔. (
13.「ARC 162D」Smallest Vertices ⭐
- Link & Submission.
- 「A.树论-Prufer 序列」
学过 Prufer 没? 学过 Prufer 没? 学过 Prufer 没?
先数 good tree, 即点 \(i\) 的度数为 \(d_i+[i\neq 1]\) 的无根树数量:
接下来数 good vertex, 仅考虑 \(u>1\) 且 \(d_u>0\) 的非平凡情况, 我们需要求出 \(u\) 为 good vertex 的 good tree 数量. 枚举 \(u\) 的子树点集 \(S\), 这里应当有 \(\sum_{v\in S}d_v=|S|-1\), 方案数:
哈! 原来方案数和 \(S\) 的长相没有关系. 随便 DP 一下就行. \(\mathcal O(n^3)\).
14.「ARC 162E」Strange Constraints
- Link & Submission.
欸欸欸咋 ARC 也放打火机啊. 出现次数大的数的可选范围 (数值和位置) 是次数小的数的子集, 那么知道了次数大的数的数量和占用的位置数量, 就能够直接计算出空余数量. 令 \(f(i,j,k)\) 表示考虑了出现次数 \(\in[1,i]\) 的数, 一共确定了 \(j\) 种数值, 它们共选定了 \(k\) 个位置时的方案数, 直接枚举 \(i\) 有多少个就能转移. \(\mathcal O(n^3\log n)\).
15.「ARC 162F」Montage ⭐
- Link & Submission.
- 「C.性质/结论」
这才是有 AtCoder 味道的题嘛.
先形象化地理解要求: 对于矩形内任意 \(2\times2\) 的子矩形, 若左上右下都是 \(1\), 则左下右上也是 \(1\).
可见, 同行同列如果同时出现 \(01\), 就可以推出其他某些格子的信息. 考虑:
? ? ? ? ? ? ? ? ? ? 0 ?
1 ? 0 ? => 1 ? 0 ? => 1 ? 0 ?
? ? ? 1 ? ? 0 1 ? ? 0 1
? ? ? ? ? ? 0 ? ? ? 0 ?
也就是说如果一个子矩阵的左上右下都是 \(1\), 那么如果矩阵中间夹了个 \(0\), 则这个 \(0\) 一定可以推导出一整行或者一整列上全部都是 \(0\).
我们不如直接把全 \(0\) 行列都抽出来, 那么剩下的矩阵需要满足:
- 每行每列都有 \(1\).
- 左上右下是 \(1\) 的子矩阵中间都是 \(1\).
画出 \(1\) 的轮廓线, 是两条从矩阵左下角到右上角的折线, 且两折线重合部分长度和为 \(0\). 设 \(f(i,l,r)\) 表示两折线上升了 \(i\) 次, 一条纵坐标在 \(l\), 一条纵坐标在 \(r\) 的方案数, 转移可以递推实现, 答案为
复杂度 \(\mathcal O(n^3)\) (\(n,m\) 同阶).