NOI 金牌导航
这里有些题因为太简单或不可做就没放。持续更新中。
1. 动态规划
1.2 数据结构优化 DP
B. 基站选址
设 \(f_{i, j}\) 表示考虑前 \(i\) 个村庄,选 \(j\) 个村庄作基站,\(i\) 必选时最小的总费用。考虑从决策点 \(k\) 转移到 \(i\),那么我们只需要处理位于区间 \([k + 1, i - 1]\) 中的村庄的覆盖情况。记这个值为 \(v\),那么有 \(f_{i, j} \gets f_{k, j - 1} + v + c_i\)。
那么怎么做呢?考虑对每个村庄二分预处理出 \(l_i\) 和 \(r_i\),表示可以覆盖它的最左端的村庄和最右端的村庄。那么我们只需要判断对于 \(p \in [k + 1, i - 1]\),是否有 \(l_p \leq k\) 或 \(r_p \geq i\)。
我们先考虑后者的满足情况再考虑前者。考虑将 \(p\) 的贡献挂在 \(r_p + 1\) 上。这样,我们每到一个 \(r_p + 1\),那么就意味着 \(p\) 不满足后者了,这时候我们考虑前者怎么维护。注意到前者对于所有 \(k \leq l_p - 1\) 都是不满足的,于是我们直接将区间 \([1, l_p - 1]\) 的 DP 值都加上 \(p\) 的代价即可。这样做显然是正确的。
需要注意的是,这题最后需要设一个虚村庄,即 \(n + 1\) 号村庄,否则显然是有问题的。维护的话直接上线段树就可以,时间复杂度 \(O(n \log n)\)。
D. 免费馅饼
由于长和宽的范围都是 \({10}^8\),所以我们应该从馅饼的角度来考虑问题。
设 \(f_i\) 表示考虑前 \(i\) 块馅饼,强制拿第 \(i\) 块的最大分数。考虑从 \(j\) 转移到 \(i\)。显然,这需要满足 \(\lvert p_i - p_j \rvert \leq 2 \times (t_i - t_j)\)。拆开绝对值后你会得到两个式子,但需要分讨 \(p_i\) 和 \(p_j\) 的大小,比较麻烦。但是容易证明我们只需要判断这两个式子是否同时成立即可。这样,原问题转化为了一个二维数点问题,直接做就行,时间复杂度 \(O(n \log n)\)。
E. 优美玉米
显然,每次拔高的区间右端点一定为 \(n\)。否则将右端点改为 \(n\) 也没有影响。
考虑直接设计 DP。设 \(f_{i, j}\) 表示考虑前 \(i\) 个玉米,拔高了 \(j\) 次后的答案。显然,如果要从 \(i ^ {\prime}, j ^ {\prime}\) 转移到 \(i, j\) 只需要判断是否 \(j ^ {\prime} \leq j\) 与 $a_{i ^ {\prime}} + j ^ {\prime} \leq a_i + j $ 同时成立即可。
使用二维树状数组优化,时间复杂度为 \(O(n k \log n \log k)\),能过。
F. 地精部落
这题的 Trick 同 AT_dp_t,且后者严格强于前者,所以我们讲后者。
设 \(f_{i, j}\) 表示前 \(i\) 个数排列为 \(1 \sim n\),第 \(i\) 个数为 \(j\) 时的方案数。由于小于号和大于号是完全一样的,所以我们只考虑小于号的情况。
显然,\(f_{i, j}\) 只能被 \(k < j\) 的 \(f_{i - 1, k}\) 转移。而对于任何一种转移,我们可以将大于等于 \(j\) 的数都加一,这样操作后的排列是合法的。所以 \(f_{i, j}\) 就等于所有 \(k < j\) 的 \(f_{i - 1, k}\) 的和。
这显然可以前缀和优化,时间复杂度是 \(O(n ^ 2)\) 的。感觉也可以线段树合并优化,这样时间复杂度就是 \(O(n \log n)\) 的,但我不想写了。
1.3 决策单调性优化 DP
B. 土地购买
首先,如果存在包含关系,那么可以去掉小的那个矩形。那么,我们按照高度降序排序后,宽度一定是升序的。这样,我们选择的矩形组合一定是若干个区间。那么就是典型的连续段问题了,可以直接斜率优化。但这题的 DP 是有决策单调性的,所以也可以决策单调性优化。使用二分 + 单调队列的话时间复杂度就是 \(O(n \log n)\)。
2. 字符串算法
2.2 后缀数组
A. 不可重叠串
显然在差分数组上做,那么只需要找到最长的出现两次且这两次不交的子串。
考虑二分答案,设这次二分到了 \(\text{mid}\)。考虑将 Height 数组中大于等于 \(\text{mid}\) 的值都标记为 \(1\),其他都是 \(0\)。这样,我们的两个后缀形成的排名区间一定是一段连续的 \(1\)。至于不交的部分,我们考虑处理出每个 \(1\) 连续段最前面和最后面的后缀,如果它们的距离大于 \(\text{mid}\) 就满足了不交的条件。
二分 check 显然是线性的,时间复杂度 \(O(n \log n)\)。
G. 公共串计数
套路地,将 \(A\) 和 \(B\) 拼接在一起建 SA,求出 Height 数组。
我们标记出 Height 数组中值大于等于 \(k\) 的位置,那么合法的后缀的排名一定形如若干个标记的连续段。这时,我们需要满足两个后缀不在一个串内,这可以染色解决。注意到两个后缀可以贡献多个子串,还需要使用单调栈统计答案。除建 SA 的部分时间复杂度线性。
3. 图论
3.7 双连通问题与圆方树
B. 铁人两项
先建出圆方树,考虑固定 \(s\) 和 \(f\),求出 \(c\) 的数量。显然,在圆方树上圆点 \(s\) 到 \(f\) 的路径中,方点代表的是必经过的点双,而圆点则代表必经过的割点。那么,对于一个必经过的点双,它内部的所有点都可以成为合法的 \(c\),所以我们可以将方点的权值赋为点双的大小。但是这样的话那些必经过的割点会算重,所以我们需要将圆点的权值赋为 \(-1\)。这样,我们只需要统计树上路径的点权和就行了。仿照树形 DP 的过程,考虑对每个点求出它的权值对答案的贡献即可。时间复杂度 \(O(n)\)。
E. 战略游戏
建出圆方树。
对于两个关键点,显然,它们之间的圆点都是合法的。拓展这个结论,对于多个关键点来说,对于一个最小的能覆盖它们的联通块,这个联通块内的圆点(除了关键点本身)都是合法的。证明显然。
然后我们发现,这不就是虚树吗!于是写了个虚树,然后就挂了。其实它并不需要虚树,我们可以仿照建虚树的过程做。具体地,先将圆点的权值上移到边上,再按照 DFS 序排序,然后求出相邻的两个点路径中的圆点个数,再加上第一个点和最后一个点的,最后除以二,就是最小联通块中圆点的个数。证明的话是容易的,考虑每条边算的次数即可。
时间复杂度 \(O(n \log n)\),瓶颈在求 LCA 和排序。
4. 高级数据结构
4.1 左偏树
A. 派遣
选点在子节点与父节点之间没有继承关系,但删除不合法点则有继承关系,故考虑删除 \(c_i\) 较大的点。对每个点维护一个大根堆,继承时与父节点的合并。删除时只需要不断删堆顶即可。时间复杂度 \(O(n \log n)\)。
B. 城池攻占
跟上一题一样的合并方式,只不过需要维护两个懒标记,参考线段树的即可。时间复杂度亦为 \(O(n \log n)\)。
4.5 重量平衡树
B. 带插入区间k小值
替罪羊树套线段树谁写啊!分块链表是好的!
区间第 \(k\) 小的套路是同 最初方块 的。值域分块,维护块内数量和单点数量,再在序列上前缀和,查询就往上跳即可。
现在重点是插入操作,考虑分块链表。具体地,每个块对应链表的一个节点,插入就暴力插入,如果块长大于二倍应有块长就将这个点拆成两个点。实现都是不难的。
需要注意的是,插入可能插在最后面,所以要在最后面插入一个虚点,即 \(n + 1\) 号点。时间复杂度是 \(O(n \sqrt{n})\),不卡常,比树套树优秀多了。
4.8 笛卡尔树
A. 棋盘
先建出小根笛卡尔树。
考虑 DP。设 \(f_{u, i}\) 表示对于笛卡尔树上的点 \(u\),去掉 与它父亲 等量的最底下的若干行后放 \(i\) 个车的方案数。再设辅助数组 \(g_{u, i}\) 表示对于点 \(u\),去掉 与它 等量的最底下的若干行后放 \(i\) 个车的方案数。最后设 \(l\) 和 \(r\) 分别表示 \(u\) 的左儿子与右儿子,\(t\) 为笛卡尔树的区间长度。
先求出 \(g_{u, i}\),显然有:
再考虑求出 \(f_{u, i}\),枚举最底下的若干行的方法,有:
暴力算的话时间复杂度是 \(O(n^3)\) 的,但是这里两个式子都是可以卷积的形式,所以理论上时间复杂度可以优化至 \(O(n^2 \log n)\) 的。
B. 星座
首先,删除是不好办的,我们考虑保留一些星星,使得这些星星合法且权值和最大。
这道题不同于上一题,我们需要按照 \(a_i\) 建出大根笛卡尔树,
考虑 DP。设 \(f_{u, i}\) 表示考虑以 \(u\) 为根的子树,保留的星星最高的纵坐标为 \(i\) 时最大的权值和。设 \(l\) 和 \(r\) 分别表示 \(u\) 的左儿子与右儿子。最后记 \(k = a_u\)。
转移的话需要分类讨论,先考虑 \(i > k\) 的情况,此时显然有:
当 \(i \leq k\) 时,只需要将上式中的 \(k\) 替换为 \(i\) 即可。
其实,随着递归的回溯,\(k\) 是不断增大的。这意味这我们只需将 \(f_{u, k}\) 赋值为可能的前缀最大值即可,即:
使用线段树合并优化这个转移,时间复杂度为 \(O(n \log n)\)。
5. 树上问题
6. 技巧与思想
6.3 分块算法
A. 区间众数
首先,维护第 \(i\) 个块内每个数出现次数和前 \(i\) 个块内每个数出现次数,这样我们可以轻松统计第 \(l\) 到 \(r\) 个块内每个数出现次数。
再维护一个 \(f_{l, r}\) 表示第 \(l\) 到 \(r\) 个块内的众数。预处理是简单的,对于一个 \(l\),将 \(r\) 从 \(l\) 开始往右扫,扫到一个块就 \(O(\sqrt{n})\) 加入一个块。这样,这部分是总时间复杂度是 \(O(n \sqrt{n})\) 的。
每次查询区间 \([l, r]\) 时,设 \(l ^ {\prime}\) 表示 \(l\) 所在块的编号,\(r ^ {\prime}\) 表示 \(r\) 所在块的编号。同块或者相邻块直接暴力做,在这里不多赘述。如果不同块,显然区间众数要么为 \(f_{l ^ {\prime} + 1, r ^ {\prime} - 1}\),要么在边角料中出现过。这样,我们暴力枚举边角料即可。需要注意的是,枚举边角料时要加入第 \(l ^ {\prime} + 1\) 到 \(r ^ {\prime} - 1\) 个块内数的个数。
时间复杂度为 \(O(n \sqrt{n})\),空间复杂度亦为 \(O(n \sqrt{n})\),不卡常。
7. 计算几何
8. 数学
8.7 莫比乌斯反演
A. 数对统计
即为求:
直接莫反,上式等价于:
先枚举约数,上式等价于:
化简,上式等价于:
直接整除分块即可。时间复杂度 \(O(n \sqrt{n})\)。
B. 周期字符串
设函数 \(f(i)\) 表示长为 \(i\) 且循环节长度恰为 \(i\) 的字符串个数,函数 \(g(i)\) 表示长度为 \(i\) 的字符串个数,那么有:
直接莫反,有:
显然,\(g(i) = {26}^i\),这意味着我们可以通过快速幂来求出 \(g(i)\)。考虑 \(O(\sqrt{n})\) 枚举 \(d\),这时我们需要求出 \(\mu(d)\)。注意到 \(n \leq {10}^9\),直接杜教筛即可。时间复杂度玄学,反正能过。
8.8 杜教筛
B. 简单的数学题
真是简单。
考虑先枚举 \(\gcd(i, j)\) 的值,原式变为:
显然,\(i\) 和 \(j\) 都是 \(k\) 的倍数,那么上式等价于:
直接莫反,上式等价于:
改变枚举顺序,依次为 \(k,d,i,j\)。显然,\(i\) 和 \(j\) 也都是 \(d\) 的倍数,所以上式等价于:
为了方便,我们定义下面的函数:
整理,原式变为:
令 \(T = kd\),先枚举 \(T\) 再枚举 \(d\),上式等价于:
显然,在 \(T > n\) 时是无意义的,那么上式等价于:
令 \(d = \frac{T}{d}\),上式等价于:
化简,上式等价于:
由于 \(\varphi = \text{id} \ast \mu\),上式等价于:
考虑杜教筛。显然,上式中 \(f\) 函数的前缀和可以 \(O(1)\) 求,那么我们只需要考虑上式中去掉 \(f\) 的部分,即 \(\text{id}^2 \varphi\)。这在杜教筛中卷上一个 \(\text{id}^2\) 即可。时间复杂度 \(O(n ^ {\frac{3}{4}})\),能过。
8.9 快速傅里叶变换
A. 力
差卷积,分两部分卷,翻转一下即可,时间复杂度 \(O(n \log n)\)。

浙公网安备 33010602011771号