Solution Set - NOI 2022
众数
Solution
有个题叫「POI2014」Couriers,这个题启示我们实际上问题等价于询问哪个数出现次数最多,最后只需要判断是否超过一半即可。
考虑线段树,对于一个序列,开一棵线段树维护上面的权值,单个序列的查询可以在线段树上面走,选择大的那一边走下去,最后的就是答案,多个序列可以考虑 \(m\) 个线段树一起走,同样选择大的一边,注意到 \(\sum m\le 5\times 10^5\),所以这样做复杂度是对的。
查询解决了,接下来考虑修改,修改在线段树上的影响不过是单点改和合并,这些都是简单的,但是注意到我们要维护每个序列的末尾,以及合并两个序列,可以使用启发式合并做到 \(O(n\log n)\)。
更优的想法是,可以使用链表的形式来维护,因为我们只需要知道末尾元素,而合并操作可以直接把一个链表的尾部元素的 next 指针指向另一个链表的开头元素,从而做到线性。
总时间复杂度线性对数,但是据说有高论可以做到线性,我还不会。
赛时我实现了这个做法,但是因为不明原因的链表写挂,所以只有 \(75\) 分。
移除石子
Solution
你先考虑怎么判无解,考试的时候我就完全不会判无解。
暂时先不考虑加石子,设计 DP 为,\(f_{i,j,k}\) 表示,目前在第 \(i\) 个位置,有 \(j\) 个操作二要延伸到 \(i\),且有 \(k\) 个一定要延伸到 \(i+1\) 或者更远,这个 DP 是容易转移的,只需要枚举新开的二操作 \(l\) 和接下来要延伸到下一个位置的二操作数 \(p\in[k,k+j]\),则 \(f_{i,j,k}\) 可以转移到 \(f_{i+1,p,l}\)。
感觉上 \(j,k\) 需要开很大,但是注意到我们其实只需要找到一组合法操作,考虑压缩状态,是不是 \(j,k\) 可以开的稍微小那么一点?
首先先规范一下我们的操作,为了使 DP 状态更少,我们考虑强制如下规则:
- 优先一操作。
- 然后,优先短的二操作。
那么首先你有几个发现,一个是相同的区间一定不会做两次二操作,因为会被转成多个一操作,还有长度 \(\ge 6\) 的二操作没啥意义,因为可以拆分。
意识到这点之后,二操作有用的就只有长度为 \(3,4,5\) 的,然后你会发现他们同时存在也没有任何意义,因为 \([i,i+2],[i,i+3],[i,i+4]\) 可以变成 \([i,i+2],[i+1,i+3],[i+1,i+4]\) 和一次对 \(i\) 的操作 \(1\)。
故,\(j\le 4\),\(k\le 2\) 是可行的。
这个时候你再理性分析一下,能不能再继续缩减,手玩会发现,\(j=3\) 的所有情况都可以被调整成 \(j\le 2\) 的情况,于是 \(j\le 2,k\le 2\) 是可行的。
据称有人减一维强行减出来了,十分膜拜。
接下来考虑加石子,一个感觉是如果说在加了若干石子使局面合法的情况下,再加上一枚其实不会有太大影响,除了某些特殊情况,讨论一下:
-
\(k=1\) 时:
- 如存在操作一,则一定有解,因为可以让操作一多减一个。
- 如存在操作二长度 \(>3\),则一定有解,你可以把某个操作二长度减个一然后添加一个操作一。
- 如存在操作二长度为 \(3\) 且 \(n>3\),则一定有解,你可以把操作二长度延长 \(1\)。
然后你会发现这种情况下无解的情况,要么全为 \(0\),要么 \(n=3\) 且全为 \(1\),恰恰这两种情况 \(k=0\) 都是有解的。
-
\(k\ge 2\) 时:
- 考察 \(k=1\) 时无解的两种情况,考虑上述中添加石子会爆炸的两种情况,你会发现全为 \(0\) 根本不可能加出来,全为 \(1\) 去掉一个石子后是无解的。
- 其余情况你可以随便选个位置加两个石子。
特判掉 \(k=1\) 的两种情况,我们的新结论是,如果添加 \(k-1\) 颗石子有解,则添加 \(k\) 颗石子有解。
于是乎,修改状态为最少需要加的石子个数,考虑个数的计算,设 \(v=a_i-j-k-l\),若 \(v<0\),则需要 \(-v\) 颗石子,若 \(v=1\),则需要一颗石子,其余情况不需要石子。
类似 DP 即可,最后判断 \(f_{n+1,0,0}\le k\)。
经历了如此复杂的讨论,恭喜你拿到了 \(40\) 分。
接下来考虑如何计数,一个感觉是,\(r_i\) 太大没啥意义,换句话说,一个数选 \(v\) 和选比 \(v\) 小的 \(v'\) 本质上是相同的,结合上面的状态分析,实际上我们只需要取 \([1,6]\) 之中的数就行了,这个是十分显然的。
这个时候就是经验了,你发现外层计数好像要 DP,内层判定好像还要 DP,DP 套 DP 硬冲就完事了!!!!1
理论上这个 DP 套 DP 有 \(100^6\) 种状态,但是你爆搜一下发现只有 \(8000\) 多种,所以硬冲就过了。
Solution
挑战 NPC II
Solution
提示里面写的很好,本题需要使用树哈希,考虑到树哈希的本质是将一个子树映射成一个数值,也就是可以方便地判断两个子树是否相等,由此我们考虑一个构造过程:
首先使用树哈希求出两棵树(下文分记为 \(T_1,T_2\))每一棵子树的哈希值,考虑如何匹配两棵树的子树,一个显然的事情是,我们希望被匹配的两棵子树得是同构的,那么我们先将这些同构的找出,剩下的子树存起来。
注意到 \(T_1\) 剩余的子树个数一定需要大于等于 \(T_2\) 剩余的子树个数,同时 \(T_1\) 剩余的子树个数必须 \(\le k\),否则无解。
考虑将 \(T_1\) 与 \(T_2\) 剩余的子树进行匹配并重复递归执行上述过程,我们希望求出某一个匹配,其中删点数量恰为某一个值,但是实际上我们并不能快速计算这个东西,所以只能暴力枚举 \(k!\) 种匹配递归。
由此,我们得到了一个复杂度十分玄学的算法,上界是 \(O(\prod_{i=1}^ki!n)\),但是似乎跑不满?可以通过。(UPD:有证明是 \(O(2^kn)\))。
笔者没有学过树哈希,所以考场上编造了一个树哈希算法,其表现不错,可以拿到 \(92\) 分,这里就不说了,下面是几个可能可以通过的树哈希算法(笔者也没有具体实现):
- 钦定一个 \(B\),满足 \(B>>h_i\),在求 \(h_u\) 的过程中排序儿子的 \(h\),从小到大执行一个类似字符串哈希的过程,即求出 \(\sum h_v\times B^i\),然后加上 \(u\) 的信息。
- 将树转成括号序列后,对于括号序列进行字符串哈希。
- 膜拜 dls:https://peehs-moorhsum.blog.uoj.ac/blog/7891
Code
冒泡排序
Solution
下面没有证明。
首先使用区间覆盖或者并查集判断无解,下文假设其有解。
判断无解的时候,可以顺带求出每一个值的最小值。
结论一:对于每一个区间,我们的最小值一定丢在尽可能左。预先丢上这些最小值。
结论二:从右往左填,局部最优解为全局最优解。
考虑如何维护每一个数的答案,首先对于每一个数的最小值 \(low_i\),预先为 \([1,low_i-1]\) 添加贡献 \(1\),对于一个被扫到的 \(j\):
- 如果其有 \(low_j\),\([1,low_j-1]\) 减去 \(1\),因为贡献转换了。
- 如果其没有规定值,求出 \([low_j,m]\) 的最小值,这就是当前点的答案。
- 为 \([val_j+1,m]\) 添加 \(1\)。
最后对于 \(val_i\) 求逆序对个数即可,时间复杂度 \(O(n\log n)\)。
Code
二次整数规划问题
Solution
大概复读一下官方题解(?)
首先先处理变量之间的约束,这是一个差分约束问题,解决这个问题的复杂度不是瓶颈,这里不讨论具体细节。
那么现在,我们的问题就变成了,有若干个数,每个数有其取值区间,满足目标函数最大。
结论一:如果有取值区间可以取非 \(1\) 和 \(k\) 的数,那么其不取 \(1\) 或 \(k\) 不劣。
证明:注意到一个细节,\(1\) 和 \(k\) 是没有贡献的。那么将 \(1\) 和 \(k\) 改成其他数只会损失掉其作为 \((1,2)\) 和 \((1,1)\) 贡献 \(G\) 的情况,但是改成 \(2\) 这两者贡献又会被加回来,\(k\) 的情况类似。
由此我们可以导出 \(k=3\) 的做法,也就是将能取 \(2\) 的取 \(2\),然后对于 \(v\) 计算答案。
同时也注意到序列这个东西其实是个幌子,我们只需要计算每个数出现了多少次,下文记 \(c_i\) 表示 \(i\) 出现的次数。
考虑将其扩展到 \(k=4\),应用结论一之后,我们去除掉一些必须选 \(2,3\) 的元素,剩下的元素可以选 \(2\) 也可以选 \(3\),假设这些元素共有 \(n\) 个,选了 \(x\) 个 \(2\),那么增加的贡献是 \(10^6(c_1+c_2+c_3)x+v_2x+10^6(c_2+c_3+c_4)(n-x)+v_3x\),这是一个关于 \(x\) 的一次函数,故最值在 \(x\) 的最值处取到,所以只有两种情况,取最大值即可。
最后考虑 \(k=5\),根据上面的思想,我们将 \((c_2,c_4)\) 作为每一个序列的代表,考虑相比于 \((0,0)\) 时序列贡献的变化,为:
存在 \(c_2,c_4,c_2c_4\) 的项,故可以划归成 \(-V(c_2-a)(c_4-b)+C\) 的形式,问题也就变成了要求最小化 \((c_2-a)(c_4-b)\)。
问题等价于平移 \((c_2,c_4)\) 后 \(c_2c_4\) 最小,对 \((c_2,c_4)\) 平移后的分布做分类讨论:
-
全都在第一象限,那么最优情况为能选 \(3\) 的选 \(3\),也就是对应 \((\min c_2,\min c_4)\)。
-
部分在第三象限,那么最优情况一定在二四象限,对应 \((\max c_2,\min c_4)\) 和 \((\min c_2,\max c_4)\)。
-
全在第三象限,那么此时答案一定在右上凸包。
我们只需要找到右上凸包,就可以用凸包点数的代价求解一组询问。
考虑如何求凸包,我们使用类似最小乘积生成树的方法,对于凸包上相邻的两点 \((x_1,y_1),(x_2,y_2)\),满足 \(x_1<x_2\),我们求出与 \((x_1-x_1,y_1-y_2)\) 叉积最大的点 \((x',y')\),仿照最小乘积生成树,左右递归下去。
每一次分治过程中我们希望解决如下问题:选 \(2\) 有 \(y_1-y_2\) 的收益,选 \(4\) 有 \(x_2-x_1\) 的收益,满足条件的情况下收益最大。
更换一下问题描述,先加上 \(y_1-y_2+x_2-x_1\) 的收益在算代价,所以就变成了选 \(2\) 有 \(x_2-x_1\) 的代价,选 \(3\) 有 \(y_1-y_2+x_2-x_1\) 的代价,选 \(4\) 有 \(y_1-x_2\) 的代价,同时变量之间有限制,这是一个切糕型网络流。
时间复杂度为 \(O(n^{2/3}(\text{Dinic}()+q))\)。

浙公网安备 33010602011771号