Change Log
- 2022.2.1. 计划优化整篇文章,修改 POI2006 部分题解(修改至 P3449)。
- 2022.2.3 ~ 2.5. 新增了大概 道绿 ~ 蓝题。
- 2022.2.20. 新增 P3462(2007), P3514(2010), P3523(2010)。
1997
首先容易区间 DP 求出 能够表示由哪个字符得到,状压存储。来个 DP 表示 前缀至少需要多少个 得到,转移有 且需满足 。 的转移枚举中间点 以及 中的所有字符 。可以预处理字符 与字符集合 合并能得到哪些字符,但是这样时空复杂度均为 ,无法接受,拆成 和 两半预处理即可。 时间复杂度 。
1998
将坐标系顺时针旋转 后,使用 Dilworth 定理转化成最长上升子序列(经典导弹拦截)。注意对于横坐标相同的点,需要先考虑纵坐标大的那个。
1999
不难看出区域颜色误差就是一些城市的人口与人口中位数的差的绝对值之和。我们有关键性质:被划分到同一颜色的所有城市一定连续。调整法容易证明。
根据上述性质,考虑一个最朴素的 DP:设 表示用 种颜色划分前 个城市,区域颜色误差之和的最小值。显然有 ,其中 表示城市 的区域颜色误差。
根据上述转移式转移,并预处理人口数量的前缀和从而 计算 ,可以做到 ,足够通过本题。
可不可以再给力一点啊?可以。
关于贡献函数 ,它有非常好的性质:它满足 四边形不等式。可以证明对于 ,有 。感性理解即可,证明留给读者。因此这个动态规划满足决策单调性,可以使用 决策单调性分治 优化,时间复杂度 。
可不可以再给力一点啊?可以。
我们猜测 是关于 的凸函数,使用 wqs 二分 和二分队列在 时间内解决,其中 是二分值域。
诶,这好像就是 IOI2000 邮局。破案了,IOI 竟然出原题。
2001
经典老题。题目相当于求 以内约数个数最多的数。
有两个性质:若用到质数 但没用到质数 且 ,把 换成 不改变约数个数但减小了数字,更优;若 的指数大于 且 ,交换 的指数不改变约数个数但减小了数字。根据这两个性质,我们只需用到前 个质数,爆搜很快出结果。
2003
好题!先求和,再调整。
由于题目给出的 是齐肯多夫表示法,所以简单地对应位求和 后,。
考虑从高往低位调整,即依次保证长为 的前缀,长为 的前缀 …… 直到整个数都满足齐肯多夫表示法,类似 数学归纳法。因为从低到高涉及进位,很麻烦。下称满足齐肯多夫表示法为 合法。
我们发现最棘手的是 ,别的都好办。由于 ,考虑一次操作 表示令 ,,。此时可能导致低位 的出现,但是问题不大,因为我们只关心 及其高位。
我们的目标是 尽可能消掉 ,自然不希望已经处理好的高位重新出现 。由于 及其高位合法,所以不会出现连续的两个 。因此,若 且 , 会令 变成 。
不妨先执行进位操作,即 ,,。由于 一定等于 ,所以进位后等于 。同时,若 ,那么继续进位到 。称从 开始不断进位的过程为 ,其代码如下:
void flush(int p) {while(z[p] && z[p + 1]) z[p + 2]++, z[p]--, z[p + 1]--, p += 2;}
注意,当 及其高位均合法时,操作才不会出错,即操作结束后 及其高位仍合法。容易证明这一点。否则可能出现数码 。如当 时,这样的进位导致 ,破坏了齐肯多夫表示法,但若 及其高位合法,则不会出现 的情况。
执行完 或 次进位操作后,,因此若 ,再执行 仅会将 变为 ,且由于 ,故现在所有 及其高位均有 ,但 及其高位不一定合法,因为可能 。由于此时 及其高位合法,所以先 ,再 即可保证对于得到的结果, 及其高位合法。
啰里啰嗦这么一大堆,只是为了严谨证明以下做法的正确性:
- 从高到低考虑每一位 。保证 及其高位合法。
- 首先 。
- 若 ,则依次执行 ,,。
- 此时 及其高位合法。
特殊情况: 令 ,,。 令 ,。不难发现我们对高位的影响最多仅是令 加 ,和普通的 是一样的,故特殊情况也一定合法。
时间复杂度分析:考虑 ,每次进位均会让 减少 ,而 op
不改变 ,故 flush
的总复杂度均摊为 ,即总时间复杂度线性。
简单贪心。将 从大到小排序并考虑每条竖线,先切代价更大的那一维。从大到小排序调整法可证(对于相同维度,先切代价小再切代价大不优),贪心策略调整法可证(将先切代价小的一维,再切代价大的一维不优)。时间复杂度线性对数。
连通性相关删边题目考虑时光倒流,求出每个猴子第一次与 连通的时间。直接 dfs 打标记即可。时间复杂度线性。
2004
状压枚举子集,时间复杂度 。
2005
本题贪心的思想还算比较巧妙:如果地板满了,我们会选择下一次被玩的时刻最晚那个玩具 放回去。证明的话经典调整法,设放了 回去,那么下次玩 时还要把 拿回来,把 放回去,相较于直接把 放回去多用了一步,不优。
维护时刻最晚的玩具,priority_queue
足矣。因为压入一个玩具时,其在堆里面对应的下一次被玩的时刻永远也不会取到,新的下一次被玩的时刻显然大于原来的,故不需要任意删除元素。时间复杂度 。
显然,基环树个数即为答案。
巧妙线性代数题。题目要求我们找到两个向量 ,使得它们的 整系数 线性组合得到的线性空间(简称整系数线性空间)等价于给出的所有向量的整系数线性空间。定义 表示向量集合 的整系数线性空间,即
如果我们能将三个向量 合并成与之等价的两个向量 ,就能够解决本题。根据基础的线性代数知识,不改变矩阵行空间的初等行变换有三种:
- 兑换:对应本题即可以任意交换 。
- 倍乘变换:对应本题即向量可以乘以任意非 整数。
- 倍加变换:对应本题即向量可以加上任意整数倍其它向量。
当然,上述性质仅在 实系数 线性组合的前提下成立。当要求系数为 整数 时,
- 兑换显然不改变矩阵行空间。
- 倍乘变换 可能改变 矩阵行空间,因为 整数乘法不可逆。如 ,前者是任意整点,后者是任意纵坐标是偶数的整点。
- 倍加变换 不改变 矩阵行空间:对于任意 ,它本质上仍是 的整系数线性组合 。对于任意 ,我们也总可以将其表示为 和 的整系数线性组合 。
很好!如果整系数倍加变换不改变整系数意义下的矩阵行空间,就可以使用 辗转相减法。具体地,考虑两个向量 ,我们能够在 不改变其整系数线性空间 的前提下,将 的某一维变为 。只需对 在这一维进行辗转相减法即可。
考虑三个向量 ,我们对 在 这一维进行辗转相减,再对 在 这一维进行辗转相减。此时 均为 ,意味着 共线。因此,对 在 这一维进行辗转相减,就可以使 ,而 变成了 零向量,对 没有任何贡献,可以 直接舍去,即此时 。综上,我们在 的时间内解决了问题,其中 是值域。
注意点:题目限制了坐标绝对值不超过 ,因此辗转相减法得到最终的 时, 和 是原坐标的 ,显然满足坐标限制。但 不一定,因此要对 取模,也相当于做了一步辗转相减(此时 所以不需要改变 )。故最终得到的坐标绝对值不超过 ,比题目限制优一个数量级。
从上述过程中,我们也可以发现一个有趣的性质:整系数 意义下,两个向量可以在不改变其张成的前提下,使其中一个向量的 某一维变成 ,而另一个向量的对应维变成原来两个向量在这一维上的 。这也是解决本题的关键性质。
因此,推广到任意维度 ,给定 个 维向量,我们可以 求出这组向量在整系数意义下的基。诶,等等?这不就是 线性基 么!
让我们更加深入地钻研一下题解区的做法。实际上两者的核心思想是等价的,均为刚才提到的性质:将两个向量的其中一个的某一维变成 ,另一个的对应维变成 。不同点在于本文的线性代数做法是从 倍加变换 和 辗转相除法 开始,推得 这一核心思想,即我们运用正确性有保证的方法,最终得到的结果是这样一个性质。而题解区做法是首先令这一条件成立,再根据得到的线性方程组,使用 exgcd 和一些数学推导求解。这也体现了 exgcd 与辗转相除的本质联系。
不妨设对于向量 ,我们要将 变为 。此时 已经确定,即 。因此,对于方程 ,容易用 扩展欧几里得 算法求得一组解,则 。这是因为 。对于向量 ,有 ,因此有线性方程组
注意该方程组的 与之前 exgcd 求得的 不同。同时我们需使 绝对值最小,否则可能出现 ,但 的情况,即对于 中横坐标为 的所有点, 不是与 相邻的那一个,这样与 相邻的点无法表示。
根据第一个方程,得到 的关系式 。带入第二个方程,得到 ,即
我们的目标很明确:找到 绝对值 最小的合法的 。把 写成 的形式(因为分母是 ),那么 ,因此 满足
注意到若满足前两条限制,则第三条限制自动满足,故忽略。为使 的绝对值最小, 的绝对值应尽量大。到这一步,大家应该都能看出 应取 。因此,。
综上,我们将原向量 写成了另两个向量 ,其中 , 用 exgcd 求解,,。对 做一遍类似的操作,再合并 (即类似线性代数解法,令 ,然后丢弃 )即可。时间复杂度也是线性对数。
另一种求解 的思路(来源于 TheLostWeak 的博客): 可以整系数线性组合出 ,否则显然不满足条件,因为 。
根据上述性质,考虑 。由于 ,所以为了使横坐标等于 ,需要为 乘以 即 的系数,得到 。由于我们可以通过向量 得到 ,因此 。同理,。故
易证若 小于上述 ,将导致存在 ,。若 大于上述 , 无法整系数线性组合出 中的至少一个。
联立后两种方法描述 的式子,稍作化简后得到等式 。这也许说明了某些性质,但笔者已经不想研究了 QAQ,感兴趣的读者可自行钻研。
POI 真的很喜欢出 单调队列!一开始看错题,以为可以来回走,以为是个神题,想了两个小时 ……
首先破环成链,考虑从 开始顺时针方向 能不能走到,也就是要满足 , …… 前缀和 优化一下即对于每个 ,都要有 ,稍做变形得到 ,经典的滑动窗口。
对于逆时针方向,同理要有 (手动模拟一下容易得到),也是滑动窗口。时间复杂度线性。
单调队列优化多重背包板子题。由于要记录转移点,时空复杂度 。
2006 (2021.12.11-12.14)
做一发出生年的 POI(雾)。
对 求前缀 ,按照题意模拟。
若 存在 border,令其最短 border 长度为 ,根据 border 的性质 1 和性质 2(见 常见字符串算法 Part 5 border 论), 就是一个合法的周期。因此只需求出每个点在失配树上的最浅非 祖先。
细节题。首先,若一个环能够到达教学楼,那么这个环上的每个点到教学楼的路径数量都是无穷大。因此建反图缩点拓扑排序,若一个强连通分量大小 或有自环则不能入队。拓扑排序同时记录路径数 表示从 到 的路径数量,对 取 。
但题目没有保证每个点都能到教学楼,所以需要对非教学楼的点跑一遍拓扑排序。注意此时若强连通分量有自环或者大小大于 是可以入队的,因为它们没有到达教学楼的路径。
最后,若出现没有入队的点,说明这个点能够到达一个能够到达 的环,因此路径数无穷大。此外,若 也不符合题意。时间复杂度线性。
对于一般的区间取 区间查询 ,我们可以用普通带 lazytag
的线段树完成。但若要求不能下传标记(否则空间炸),不能 pushup
(否则时间炸,因为一次 pushup
要进行大小为 的线段树合并),那就有些棘手了。
一个技巧是标记永久化,在更新路径上将维护的区间 对修改值 取 ,在所有拆分区间处将懒标记 对 取 。查询时求递归路径上所有懒标记的最大值,再与拆分区间处维护的区间 取最大值。
实际意义: 表示维护的区间 ,而 表示 没有被下传 的修改值的 ,所以区间 的最大值为 与 到线段树的根上所有结点的 的最大值。因此查询时需要整个递归路径的 。时空复杂度 。
世 界 线 收 束。以前在小 b 那儿做过的题目,现在换种方法解决:设 表示第 行距离 的最近坏点,设 表示距离 的最近坏点,那么有:
写成 的形式,斜率优化即可。求出距离后并查集维护连通性容易做到 。
切比雪夫转曼哈顿裸题。进行 , 的变换后两维独立,求 使得 最小是经典问题,找带权重心即可。注意由于两维重心 奇偶性不同导致转回来的时候坐标出现小数,因此需检查 与 ,若奇偶性相同则转回切比雪夫求最小值更新答案,其中 。以及求切比雪夫距离之和时需要 __int128
。时间复杂度是排序的线性对数。
一个新编号只能被一个学校占用,不难想到带权二分图匹配。最小费用最大流即可,如果没有流满说明无解。时间复杂度玄学,一个非常松的上界是 即 。
CF526G 的弱化版。找到直径一端作为根,长链剖分取 个叶子即可。
比较基础的凸包题目。
考虑枚举三角形的三个点,我们必须做到 判断三角形内点的价值之和。这可以通过预处理 表示向量 逆时针方向与凸包之间形成的区域包含的点的价值之和,然后用总价值减去 得到。由于三角形包含边界,所以 不包含边界。
如何预处理呢?枚举每个物资 ,顺时针二分找到第一个位置 使得 在 的逆时针方向,即 ,此时所有在 顺时针方向直到 的所有点 的 都需要加上 。通过破环成链 + 差分做到。
注意特判在顶点上的物资。时间复杂度 。 有 的常数,可以通过。
每条路径片段的限制形如在片段中出现的相邻两条边必须先后走,因为题目限制一条边有向边仅出现一次。
所有限制形成一条边先后走的关系的链(类似 CSP2019 T4 树上的数),将这条链缩成从起点到终点的一条边,然后跑欧拉回路。最后输出这条边时要再展开成链,因此要记录每条链上的结点顺序。
若限制关系出现环或分叉则无解,这可以通过并查集或链表维护。时间复杂度线性对数或线性。
有趣的思维题。考虑到最后必然是行或者列被删完,所以我们不妨设行被删完。
接下来,考虑固定左右各删去多少列,即设 表示还剩 这些列时,尽量删行 之后剩下来的行数的区间 ,因为我们要让行尽快被删完。
区间 唯一,反证法可证:假设存在另一个区间 ,不妨设 ,那么可以删到 ,与 “尽量删” 的定义矛盾。同理,若 ,我们也可以删到 。
考虑如何求出 。显然,它要从 和 转移过来。如果 最左边一列能删掉,即 ,那么 继承 。同理,若 最右边一列能删掉, 也可以继承 。任意继承不会影响复杂度:均摊证明时间复杂度是 。
同理,假设列被删完再做一遍上述算法即可得到正确答案。
还算有趣的动态规划。遇到区间划分题首先考虑 DP,设 表示以第 个单词结尾为一行,且这一行长度为 的最小答案,有 ,其中 满足 。直接转移的复杂度为 (枚举 算出对应的 )。
不过注意到很多 都是空值,说明这个定义有些劣。不妨修改定义,设 表示最后一行为 的答案,再设 表示 即 组成一行的长度,那么有:
时间复杂度优化为 ,但仍无法接受。使用拆绝对值的技巧,维护 表示 , 表示 。对于 对应的转移位置 ,我们只需找到最后一个位置 使得 ,那么 可以由 关于 的前缀 加上 ,以及 关于 的后缀 减去 得到。
又因为固定 时, 随着 增大而增大,这说明 从 处转移时的 随着 增加而递增,因此对每个位置 维护分界点指针即可做到平方。
究极神仙题!读完题目,纷繁复杂的限制让我们无从下手。从哪个条件作为突破口呢?肯定是最严格的异或限制。
异或有性质 。对应到题目中,就是若序列 有 个数确定,则未定数只能等于所有确定数的异或和。这启发我们思考,有没有一种可能,未定数对应的限制 非常大,以至于无论 个数怎么选,它们的异或和总不大于 ,这样我们就可以很方便地用乘法原理求出答案。
实际上有可能!考虑第 位,假设存在 使得 这一位为 ,但 为 ,说明若所有数字在第 位及其高位异或和为 ,那么无论其它数字低 位怎么填都符合条件,因为 在第 位小于 ,所以接下来的低 位没有限制。
这启发我们直接枚举所有 与 的最短 LCP,即 存在 使得 在第 位为 但 为 ,且 高于第 位的部分与 相同 的位数 。这样,我们只需把任意一个 的系数变为 (因为它依赖于剩余数的异或和),剩下的系数用乘法原理乘起来即可。
具体地,考虑我们关心什么:第 位异或和为 且存在 。这启发我们设计 DP 表示考虑到第 个数,第 位异或和为 且是否存在 。根据乘法原理与实际意义转移:
若 第 位为 ,那么 可以选择 :选 的方案数为 ,选 的方案数为 。从 转移到 时,系数为 ,表示钦定 的系数为 。
若 第 位为 ,则只能选 且方案数为 。
最后,若 比 高的位的异或和为 才能计算当前位贡献 ,因为钦定了高位 都取 。注意全零序列会被统计到,因此最后答案减 。时间复杂度是优秀的线性对数,所以为什么数据范围这么小?
总结一下,对于位运算相关 有限制 的计数题,首先考虑 最严格 的限制,并尽量 独立每一位,如果做不到就按顺序考虑每一位的限制。
还算有趣的 DP,感觉难度没有黑牌。
奇奇怪怪的限制 + 很小的数据范围,动态规划没跑了。注意到我们根本不需要知道序列长什么样,只需每种玩具放的个数以及最后两个玩具是什么就可以转移。因此设六维 DP 表示放了 个 ,分别标号为 ,最后两个玩具分别是 和 的方案数,转移直接枚举下一个放什么,检查一下是否符合题意即可。
空间复杂度可通过滚动数组优化。时间复杂度四方,有 倍常数。
神仙题!看到题目,我的想法是如果 能接到 后面,说明 是 的前缀。因此,对枚举每个 的每一位 ,求出 在 中的出现次数,以及 是否是回文串。这可以通过简单的字符串哈希在线性对数时间内做到。
注意到我们根本没有用到 是回文串的性质。这好吗?这不好。我们有一个更强的性质:在 是回文串的前提下, 是回文串 当且仅当 它们的 最短回文整周期串相同。充分性显然。
在证明必要性之前,我们给出一个引理:若长度为 的 回文串 存在 回文 周期 ,则存在长为 的 回文整周期。用数学归纳法证明如下:
-
当 时,显然成立。
-
设串 ,,即 。设 ,显然 。设 表示 翻转后得到的串。
由于 都是回文串,故 。因为 是 的前缀, 也是 的前缀,所以 即 回文。故 。
因为 是 的前缀,所以 。同理,。这说明 是 的回文周期。
-
这是一个递归式的子命题:若长度为 的回文串 存在回文周期 ,则存在长为 的回文整周期。若子命题成立,则原命题成立。
-
由于 ,类似辗转相除法,因此必然出现 的情况,此时 。故原命题成立。
必要性:考虑反证法,设 最短回文周期对应的回文串为 (注意周期是长度,但为方便说明,下文省略 “对应的”), 的为 。不妨设 ( 时显然若 回文则 )。
-
首先, 不可能是 某个整周期回文串,否则 最短回文周期可以是 ,矛盾。
-
当 时,因为 ,而 和 是回文串,所以 。故 ,即 是 的回文周期。
根据引理,这说明 存在回文整周期 ,从而有 的最短回文周期不大于 即小于 ,与 的定义矛盾。
-
当 时,因为 和 是回文串,所以 。这说明 是 的回文周期。
根据引理, 存在回文整周期 ,从而有 的最短回文周期不大于 即小于 ,与 的定义矛盾。
综上,我们只需 KMP 求出每个字符串的 数组,易证若 整除 则 是最短回文周期字符串,否则最短回文周期字符串就是 本身。
每个最短回文周期字符串对答案的贡献为 ,其中 表示它作为 个串的最短回文周期字符串出现。为此,我们需要排序并检查相邻两个最短回文周期字符串是否相等。时间复杂度线性对数。
2007
题目相当于求给定图的补图的连通块数量,直接做时间复杂度显然无法承受。注意到对于当前节点 ,我们只需找到第一个不与 相邻且没有被访问过的节点打上访问标记并入队,通过双向链表 + dfs 实现。时间复杂度 。dfs 应该做不了。
将高度相同的相邻位置连边,对于每个极大连通块,若与其相邻的位置高度均小于连通块高度,则是山峰。同理,若与其相邻的位置高度均大于连通块高度,则是山谷。时间复杂度平方。
转化题意,求根到某个节点经过的特殊边数量。考虑维护每个节点的答案,一次修改就是子树 ,dfs 序拍平,BIT 维护,时间复杂度线性对数。
任意两个砝码重量互成倍数说明最多只有 种重量不同的砝码。贪心能放大的就放大的(因为大的一定能被换成小的,但如果放小的让大的没地方放,可能导致答案更劣),最后再调整。调整的方法即从大到小枚举每一种重量,如果有比它轻的砝码没放完,就把它去掉,然后放更小的砝码。类似上面的贪心,去掉后优先从大往小放。时间复杂度线性对数。
关键性质:如果 能到最左边,那么 也能。因此,能够到达所有道路的初始位置一定是一段区间 ,满足 能到最左边但 不能,且 能到最右边但 不能。
设 表示使 能到最左边,最少需要修建多少条路。明眼人可以看出这是 减去 的 LDS,但是我没有看出来(大雾)。提供一个新的思路:考虑枚举从 向左边的所有道路,设其高度为 ,我们设 表示 走的道路的高度为 时,走到 最少需要新建多少条路。再枚举下一步走的 原有 的道路是哪一条,有转移方程
初始值 。后面的 是因为根据定义,从 到 走的都不是原有道路,因此要新建 条道路。 的原因显然。将贡献拆成 ,变成一个经典的二维数点, 的有序性(从小到大枚举位置)自然地使用扫描线,把问题降了一维。我们需要支持单点修改,以及查询后缀最小值。由于查的是后缀,信息不需要可减,所以树状数组维护即可。而 显然就是 。
对于 同理,转移方程变成了 ,同样用 BIT 维护。
根据一开始的结论,区间 合法当且仅当 ,因为向左边和向右边的道路独立, 和 只是做简单的加法。注意到 具有单调不降, 具有单调不升的性质,因此考虑按从小到大的顺序枚举 ,合法的 随着 的递增,显然单调不减,只需用指针维护即可,该部分时间复杂度线性。
总时间复杂度是树状数组的线性对数。实际上 LIS/LDS 和我的动态规划应该是在干同一件事情 qwq,只不过我想复杂了。
若天然气井 和中转站 配对,对答案的贡献为 。因此答案为所有天然气井的 之和加上中转站的 之和。
2008
不难发现宽度 无用。考虑若 ,那么 前面必然要贴一张海报,因此用单调栈维护,时间复杂度线性。
合法的分割方案最多仅有 种,因此 dfs 枚举每个数是否被分进第一个集合。直接使用 C++ 自带的 __builtin_popcount
比手写 popcount
快不少。
换根 DP 板子题。
2009
由于我们只关心上一次检票是在什么时候,考虑设计动态规划状态 表示第 次检票在第 站时最多能够查到多少人的票,转移方程即
这是因为新的被查票的人必须得从第 站之后上(否则之前就被查了),在过了第 站之后下(否则查不到)。直接做复杂度 ,显然无法接受。
D / D 动态规划通常设计贡献函数 ,预处理或推柿子从而快速计算 。设 表示 ,朴素预处理后复杂度变成 ,仍然无法接受。
考虑更快地预处理:我们没有必要为每个 都重新算一遍,可以利用已经算过的结果递推。不难发现 ,这样即可做到 ,再加个后缀和优化,预处理就是平方的。因此时间复杂度 。
POI 真的很喜欢出 单调队列!
字典序最大给予我们贪心的思路,即优先选择最大的数字肯定更优,若数字相同则尽量选更前面的,因为这样剩下来的选择就更多。如 ,选前面的 就比选后面的 好。
但是有 的限制,说明如果我们选最大的,可能导致后面没法选了。因此不妨设我们在选 ,我们只能从下标为 的数当中挑选,因为如果 再大一点,那么无论如何我们都选不齐 个数。实现就是经典滑动窗口,若当前数等于单调队列队尾则不弹出,保证了相同数优先选择更前面的。时间复杂度线性。
因为任何操作不改变每一行和每一列由哪些数组成,只是改变它们的顺序,故只需判断 每一行和每一列的数字能否对应上,即对于 的每一行 ,存在 的某一行 ,使得 可重集 ,且一行 与一行 唯一对应,对于列同理。
由于数字无序,可以排序后哈希(如字符串哈希),也可以使用不依赖于数字顺序的哈希方法(如 ),再看 的每一行(列)的哈希值是否能够一一对应(简单的检查方法是排序后相同排名的数相等)。前者时间复杂度是 ,后者时间复杂度是 。效率差距较大。
2010
找出原图任意一棵生成森林黑白染色,若存在孤立点则无解,时间复杂度线性。
什么哈希和哈希表水题,时间复杂度是调和级数的 。后缀数组被完全碾压了,严格 的玩意儿(大雾)。
什么子序列自动机裸题。设每个序列 第一个没有被匹配的元素为 ,位位置为 ,依次遍历序列 中的每个元素 ,将 的所有 的匹配位置 ,即 ,,可以用 vector 或邻接链表辅助实现。若最终 则是 的子序列,否则不是。这是 离线 做法。若在线容易 vector + 二分实现。
直接二分 + 哈希太 low 了,借鉴 manacher 的思路,我们对每个位置(以两个字符之间作为回文中心)求出最长 anti-symmetry 半径,注意到这个类似 manacher,也是可以记录最右边的回文区间,快速继承和扩展做到均摊线性。
多组询问要求我们必须使用线性做法,而一个区间满足条件等价于其平均值 ,即令 表示 的前缀和,则 是区间合法的充要条件。
乍一看没啥思路,似乎要数据结构维护,因为我们需要查询 的所有数的最小下标( 之后的位置没有贡献,可以不管)。但就算这样也得排序。
观察性质,注意到若 且 ,那么 不会作为区间 左端点 出现,因为 更优。同理,若 不会作为区间 右端点 出现,因为 更优。换句话说,只有 前缀最小值 的位置才会作为区间左端点,后缀最大值 的位置才会作为区间右端点。
因此,两遍单调栈求出前缀最小值和后缀最大值对应的位置,根据单调性只需用两个指针维护。具体地,从左到右遍历每个前缀最小值,找到最右边的一个后缀最大值使得该最大值不小于当前的前缀最小值。由于前缀最小值在不断减小,故其对应的后缀最大值的下标也单调不降,用指针维护即可。时间复杂度 。
DP + 博弈趣题。一个人肯定取剩下来所有数中最大的 个数,否则会把大数留给对手,不优。因此,设 表示还剩下 个数时,先手能达到的最大分数,枚举选完还剩下几个,有转移
注意 是从小到大排过序的, 即答案。用一个变量维护即可。时间复杂度线性。
首先 two-pointers 求出距离每个点第 小的点,连出基环内向森林,求每个点走 步到哪个点。可以快速幂线对解决,但是没有直接拓扑排序找环 + dfs 优美。静态 级祖先直接用栈维护就好了。时间复杂度线性。
POI 真的很喜欢出 单调队列!直接 two-pointers + 两个单调队列就做完了。时间复杂度线性。
2011
元素权值仅有 和 一定是非常重要的限制。考虑固定左端点 ,右端点 从 的过程。设 之和为 ,容易证明若 且 不能被表示为以 开头的某个子串和,则 一定可以被表出。否则至少存在一个元素权值不小于 。
因此,考虑找到最长的后缀 使得 (即找到最小的 使得 ),则根据上述性质, 一定全部能被表示出来,因为若 不能被以 开头的某个子串和表出,则 一定能被以 开头的某个子串和表出,所以 一定能被以 开头的某个子串和表出。同理,最长的前缀 同样满足该性质。
因此,求出开头和末尾的连续的 的个数 。若 ,说明 之和大于 之和,用后缀来做。否则用前缀来做。可以通过翻转序列避免分类讨论,因此不妨设 之和更大。
设 表示 之和等于 。注意 可能不存在,但此时根据上述性质, 存在。
- 若询问的 ,则若 存在,输出 。否则输出 。
- 否则,若 且 与 的奇偶性相同(因为接下来只能让 往左移,每次添加 ),则输出 。
- 否则无解。
时间复杂度线性。
若 在群里,则所有 且是 的倍数的数也在群里。这是因为 取到了所有这样的数。证明:设 , 且 不在群里,这意味着 即 无解,根据裴蜀定理,它等价于 即 ,矛盾。证毕。
因此,考虑枚举这个 ,若合法则答案即 ,即我们需要找到最小的合法的 。如何判断合法:不妨设 , 首先得是密码与 的 即 的因数,其次任何 不能是 的倍数。
考虑后者限制:给所有 打上标记,从大到小枚举 的每个因数 ,若 被打上标记,则 也应被打上标记(其中 表示能整除 的 的质因子),表示若 是某个 的因数,则 显然也是。
剩下来没有被打上标记的所有 的因数 ,若 能被 整除则合法。找到最小的这样的 ,则答案为 。
打标记的过程用哈希表实现,时间复杂度 。 表示 的质因数个数。
设 表示以 为一端的需要经过的边的数量。对于一条回路,所有点度数均为偶数,因此一次操作后 的奇偶性不变。故若存在 使得 是奇数,则无解。否则,注意到有解是需要经过的边形成的图的每个连通块均存在欧拉回路的充要条件,对这张图跑一遍欧拉回路。由于要求不能经过相同的点,而路径上相同的点之间也一定是回路,所以借助栈把相同的点之间的回路弹出。时间复杂度 。
对于不需要经过的边,可以直接忽略,这是因为是否有解与这些边无关:如果 均为偶数,我们必然能构造出一种不经过需要修改的边,反之无解。
首先二分答案,问题转化为若选一个点能覆盖距离 的点,要覆盖所有关键点至少要选多少个点。直接贪心似乎不太行,考虑设 表示 子树内最远的未被覆盖的 关键点 与 的距离, 表示 子树内最近的被选择的节点与 的距离。
初始值为 , 初始值为 。若 本身是关键节点,则初始化 。转移时 ,。
由于若 ,则 子树内对应的最远未被覆盖的关键点可以被覆盖,因此可忽略,即令 。否则,若 或 为 根节点 且 ,则需要选择 ,令 ,。
时间复杂度线性对数。预处理 dfs 序后每次 DP 可以直接递推,不用递归,有效减小常数。
2012 (2021.12.14-12.19)
很好,限制非常差分约束。建出图来,先跑一遍负环判无解。但如何满足不同的 值数量最大呢?差分约束显然无法解决这样的问题。然后就不会了(大雾)。
首先,不同 SCC 之间独立,因为我们可以将两个 SCC 之间的距离拉得任意远。而一个 SCC 内部的答案就是任意两点最短路径的最大值 :使最短路距离增加的只有一类边,而一类边的边权仅有 ,因此若 的最短路径 ,那么从 的路径上所有点必然取遍了 这 个值。
由于图是稠密图,因此使用 Floyd 算法求解任意两点之间的最短路。答案即每个 SCC 的答案之和。时间复杂度三方。
一开始看错题咧!看成可以交换任意两个字符咧!不过也可以做,而且复杂度线性。
设 在交换后移动到了位置 ,则题目即求使得 的 的最小逆序对数量。显然,两个相同字符的相对位置不变。即若 ,那么不会出现 。否则交换 更优,因为可以减小逆序对数量。
因此, 中的每个字符唯一对应了 的一个位置,求出 后树状数组求逆序对即可。时间复杂度线性对数。
考虑在 和 之间连边,题目相当于在这张图上撒 个关键点,求距离每个关键点最近且非本身的关键点的最小编号。对每个点记录距离该点最近和第二近的关键点距离与编号,一遍 BFS
即可,但是常数太大,不开 O2 难以通过。
设 表示 的质因子个数,则 。考虑枚举 ,那么减号后面的部分就确定了,对于一个固定的 ,我们显然要让 这一二元组最小,其中 表示 值为 的最小位置。
考虑枚举 的倍数 ,求出 ,设为 以及取到最小值的位置为 。 那么对于所有 ,我们用 和 互相更新。 就相当于上面的 ,而 充当了使得 最小的 。
每个 都会被枚举到,因此算法正确。时间复杂度是调和级数的线性对数。由于小常数,成功拿到了最优解(2021.12.19)。
定义 的祖先表示从 一直走出边遇到的第一个在环上的结点,这个可以通过一遍 dfs 处理得到。处在同一子树(即奇环内向树的环上每个结点拖着的 “尾巴”,是一棵树)内的询问 就是树上 LCA,预处理倍增数组。
除去上一种情况,若 根本不在同一棵基环树上,显然无解,否则我们先跳到 的祖先 ,有两种选择: 顺着环走到 ,或者 顺着环走到 。两种方案按照规则取更优的那个即可。时间复杂度线性对数。
二分答案。对于固定的 ,首先考虑没有 的限制。
因为 可写成 以及 ,故我们只需从左往右扫一遍 ,从右往左扫一遍 ,然后求出原 与新 之间的差 。
正确性(分为合法性与最小性)证明:
- 合法性:因为 操作进行完毕后满足 ,而 操作后满足 ,且不会破环 的性质(因为 非负),得证。
- 最小性:对于 操作,若 ,我们不得不用 的代价填平 这个位置,否则不满足条件。 同理。
接下来考虑 的限制,显然还要用 更新 ,但我们没有足够的时间对每个 都这样暴力计算。稍作转化,我们就是要找到所有这样的 使得 ,然后将代价加上 。
考虑 变为 的过程, 左边的位置 的 会增加,即限制放宽,那么第一个 的位置 会向右移动。同理,对于 右边的位置 ,最后一个 的位置 也会向右移动(因为限制变严格了)。
同时,我们知道 的区间内所有位置都有 ,以及区间外的位置都有 (否则会出现相邻两个数之差的绝对值大于 的情况,因为我们是用斜率绝对值为 的直线去切这个 “山峰”,而任意位置的斜率绝对值不超过 ,故切到的一定是一段区间),所以可以用前缀和与等差数列求和公式快速计算 处的答案。时间复杂度 。
先将所有 的边 合并,剩下来所有边能加就加,用并查集维护连通性,时间复杂度线性对数。想了好一会才会做(小雾)。
注意到对于一个固定的 ,我们只关心前 个需求为 的顾客,便可断言接下来需求为 的顾客不可能拿到代金券,这一点显然。
因此,若当前需求为 的顾客数量 ,那么可以跳过剩下来所有这样的顾客。直接暴力模拟,时间复杂度是调和级数求和产生的 ,可以接受。
好题,一开始一直在想 的 背包可行性做法,发现无论如何都不可做。但是背包问题并不一定只能装 ,我们要充分发挥 的值域带来的信息。
由于背包不可删除,所以按顺序将物品加入背包方便回答,故将询问离线处理。
设 表示要用左端点小于当前位置 的所有物品组合出价值 ,所需物品右端点最小值的最大值。其中 是不断递增的,与此同时回答对应的询问。
不妨设要加入 ,根据我们的策略有 递增,转移方程如下:
对于一次询问 ,显然只能用 的物品,因此对于在加入 之前先要回答所有 的询问才能保证正确性。在此基础上,若 说明可行,否则不可行,这一点结合 的定义容易理解。
综上,时间复杂度 。
有长为 的周期 有 的 border。因此,枚举区间长 的所有因数 判断是否有 的 border 即可。时间复杂度 。
由于若 是周期,那么 也是周期,因此可以不断除以 的质因数判断,即从小到大枚举所有 的质因数 ,不断将 除以 直到不是周期或不能整除位置。时间复杂度 ,拿到了最优解(2021.12.19)。
设 为答案,可以证明在 的最小斐波那契表示(题目定义)中,必然出现 或 ,其中 且 最大(一开始的思路),预处理 较小时的答案就可以玄学复杂度爆搜了。
甚至可以证明若 则选 更优,反之选 更优,这样贪心的复杂度是对数,真是惊为天人。不太会证明(大雾),具体可以看洛谷题解区 这篇博客。
将给出的 和要求的 都从大到小排序,,,这一点显然。
先考虑已知一些数时,如何推出剩下来的数:假设 已知,它们两两相加可以形成一些和 ,用可重集 减去可重集 ,我们能得到一个最大数 ,它只能是 的和,否则与 的最大性违背。
因此,我们断言如果确定 ,那么可以在 的时间内得到整个 :找到可重集 ( 的定义如上)中最大的数 ,反推出 ,用 与 的和更新 ,再找到下一个最大的 反推出 ,以此类推。根据 的单调性可以用指针维护 。 由用 通过 map
打标记产生。特别的,若求出的 或 或 则钦定的 无解。
接下来考虑如何求 :注意到 仅有可能小于 ,因此 在从大到小排过序后的 中下标不会超过 。考虑直接枚举这个下标从而解出 和 。
综上,时间复杂度三方对数。由于大部分下标很快无解,因此常数非常小。
大大大大大大大神仙题!我初始的想法是对整棵树进行一遍 dfs,将所有儿子按照 从小到大排序,先考虑 非零的那些点,若已经处理过的子树大小之和 加上当前儿子 的子树大小等于 ,说明 的子树内的值域唯一确定,为 ,对 进行 dfs,否则直接返回。这保证被深搜到的结点的值域被唯一确定,而儿子的值域确定建立在父亲的值域确定基础上,因此遇到第一个不符合的子结点就要立刻返回。
很显然,这样是错的。原因是我们没有考虑到已经被钦定的 值。例如 值较大的结点 有较小 值的儿子 ,当我们考虑 父亲的所有子结点时,就不会将 的占位计算在内。
一个神仙想法:考虑每个结点的最大可能 值 。记 表示 的最大的没有被钦定的 值,这可以通过对于所有被钦定的 值令 ,然后 从小到大扫一遍 预处理出来。那么 即:
记 表示 即 值等于 的数的个数的前缀和,由于保证有解,故 。我们断言 值为 的结点的 值可以被钦定为 当且仅当 且 。这是因为若一个或多个 值对应多个空余的 值,则它们全都不能被确定,或者说 说明前 个值已经被 个位置内部消化,就算这 个位置没有唯一确定一个 值,后面的位置的 值也不可能 (否则就无解了)。那么就做完了,时间复杂度线性,凭借小常数拿到了最优解(2021.12.19)。
好题!区间操作转化为差分数组 的端点操作。一次 可以和一次 相抵消,因为若 的位置在 位置之前,就是区间 ,否则就是区间 。同理, 和 可以相抵消。
首先考虑对每个差分值单独求解,即解不定方程 。设 ,若 则无解,这是裴蜀定理。否则在一开始调用一次 exgcd
算法解得 的一组特解,再通过对每个 乘上 得到 的特解。
由于一个 的贡献为 ,而最终答案(首先不考虑可行性)为所有这样的贡献之和除以 (因为两两配对)。因此尝试根据特解找到 最小的特解:若 不是最小且 不是最小,那么 必然不是最小,因此我们只需要检查 和 分别取到最小非负整数和最大负整数的情况即可。
当前的 除以 是答案的下界,但并不能保证可行性,因为我们需满足 (两两配对)。由于当 时必然有 ,所以只需考虑 。
根据特解的形式 ,当 时,我们需要进行 (一定是个整数,因为差分数组之和为 )次将某个 加上 ,并将其对应的 减去 。 时分别为减去 和加上 。称这样的操作为对 进行一次调整,调整的代价即新的 减去 。
容易证明对一个数调整的代价随着调整的次数增加,仅在 或 改变符号时增加,其它时候不变,因此我们可以用一个堆维护这个过程:每次取出代价最小的 并弹出,在需求次数与不改变符号的前提下尽可能多地调整。若经过调整,需求次数为 则算法结束,否则将新的调整代价压入堆。这样的时间复杂度是严格 ,因为 其中任意一个改变符号的才会使代价改变,一共会最多发生 次,因此我们最多会向堆内压入 个数。
一个奇妙的性质是 在 级别(根据 感性理解,不会证明),这使得我们可以从堆中取数时仅进行一次调整就塞回去。时间复杂度也是线性对数。
启发:我们可以尝试先忽略问题的一些限制从而得到基本的解法,然后在此基础上考虑限制,进一步求解问题。
每个连通块独立,单独考虑。对于一个连通块 ,显然 ,故其自由度 ,即一旦钦定连通块内任何一个 ,则整个连通块确定。
不妨将连通块内的点编号为 ,考虑用 表示 。根据题目的限制 ,我们知道最后每个 都能被写成 的形式,其中 。因此,找到 的任意一棵生成树,求出 和 。
与此同时,对于非树边 ,若 与 相同,说明我们能解出 。此时可以判断无解:有两条非树边解得的 不同,或 不是整数(即 ),或 不在 范围内。相反,若 与 不同,则需检查 。上述操作可以一遍 DFS
完成。
接下来,若 被钦定,那么 也已经固定下来,检查每条边是否满足要求以及 是否在 范围内,判断无解。
否则,根据若干组 的不等式,我们可以解得 的取值范围 。我们知道 的总和为 ,记 ,,,则代价为 。显然,该式的最小值与最大值在 等于边界值时取到,分 和 两种情况讨论一下即可。时间复杂度线性。
世 界 线 收 束。法一是按 从小到大贪心,对 做前缀和,那么 合法当且仅当 都 。此时我们选择 且令 减去 。线段树维护区间修改区间最值。
法二就很巧妙了:考虑当前剩余货物 ,从小到大枚举每个 。若 说明可以暂时选 ,。否则若 大于已经选的某个 ,我们可以贪心地去掉 选上 ,。就不证了。可以用优先队列 priority_queue
维护。时间复杂度都是线性对数。
好题!不难发现若 循环相同则它们可以分别被写成 和 的形式。因此题目相当于:对于 的每个 border 长 ,求 去掉 前缀和 后缀后最长的不重叠 border 长 ,则 即答案。
是好求的,但每个 的 border 就不好求了。考虑 所有这样的子串串 , 的 border 掐头去尾后变成了 的 border,因此 。
根据这一性质,我们从大到小枚举所有 ,维护长度 表示 的最长不重叠 border 长。当 时,令 ,然后不断减小 直到 是 的一个不重叠 border 长。势能分析, 的移动距离不超过 。
判断字符串是否相等使用哈希,自然溢出哈希会被卡。求 的所有 border 直接 KMP 就行。时间复杂度线性。双 倍 经 验。
编号并不是很连续(大雾)。注意到 只有可能是 的形式,因此数量级为 。
将 离散化,直接暴力 DP 每个 是必胜还是必败态,时间复杂度线性对数。
2013
当前位置 时,每个出租车会浪费 的路程。因此贪心选择路程大的出租车先打,这样浪费的路程就更少。调整法可证。
此外需要预留一个路程 的出租车,这样在 时可以一步直达,不难发现选择路程最小的符合要求的出租车最优。时间复杂度是排序的线性对数。
考虑每次删去一段连续的 白和 黑,最后倒过来输出正确性显然。用栈 + 前缀和维护即可。时间复杂度线性。
注意到若 之间存在长为 的路径,则必然存在长为 的路径,沿一条边来回走就可以做到,因此奇偶 bfs 即可。直接开 的数组没法接受,把询问离线下来,对于每个起始位置单独回答,空间复杂度线性,时间复杂度 。
挺有意思的一道题目。考虑枚举每个点,如果没有被覆盖,那就直接在这个地方建座塔,然后把所有覆盖到的点删掉。正确性是因为存在大小小于 的点覆盖集,因此每个点至少与一个点覆盖集中的点相连,在每个点建塔都能覆盖到与所有与该点相连的点覆盖集中的点所能覆盖的点,故贪心正确。
同时,一个点最多仅会作为一次与某座塔距离为 的点(因为在此之后所有相邻点都被打上了标记,自然不会再作为塔),遍历其所有出边打标记。故时间复杂度线性。
没看出来是 DP,直接贪心,枚举最终的 段 ,符合要求当且仅当 为空或 且 为空或 ,因为 都得是 ,而 都得是 。
设 表示将 操作成全 的代价,前缀和预处理。 表示将 操作成全 的代价,后缀和预处理。运用贪心的思想可知 段 一定是 的极长 段,前面可以再带一个 (即 且 ),此时代价为 ,因为 ,需要 的代价将 变成 。此外还要用所有 更新答案。
two-pointers 维护答案,时间复杂度线性。
2014
由于 的贡献仅有 ,因此将 压入队列和队尾 比较时,若 或 ,说明 不劣于 :当 时,显然有 。时间复杂度 。
2015 (2021.12.8-12.10)
考虑增量法,实施维护右端点 时每个左端点的贡献。设 表示 在 之前倒数第二次出现位置, 表示最后一次出现位置,那么 加上 , 减去 , 区间修改全局 ,线段树维护即可。
打表猜结论题。首先这道题目长得就一脸可以打表的样子,所以我们先通过 DP 求得一点小数据的 值。
输出到 ,发现一个比较明显的分割点在 这个地方:因为 所以它是最后一个 值为 的数,显然若 则 。这给予我们第一个思想:当 很大的时候, 的组合能够生成的数覆盖了几乎所有 之间的数,以及当 时,必然有 。
但再观察表,发现在 的前面有一些 “超重” 数,它们的 值为 。乍一看似乎没啥规律,不过仔细思考后可以发现,这些超重数 与 之间的差 ,应该就是所有 的 。毕竟 应该由 的平方之和减掉一些数的平方得到,但如果它们的差()即要减去的数不能由若干个不同的完全平方数之和得到,那么 也不能由 减去一些不同的完全平方数得到,这说明 不得不大于 。
接下来我们证明在 足够大的时候,一定有 ,其中 为使得 的最小的 且 不能由若干完全平方之和表示:设 ,由于不能被若干完全平方之和表示的数有限(共有 个且最大值为 ),所以 时 ,因此 ,这说明 可以由 减去若干完全平方数得到,故 。
综上,我们有如下算法:首先暴力求出 比较小时的 (大概到 级别就够了,设范围为 ),若给定的 属于 “比较小”,即 ,直接输出答案。否则二分求出最小的 使得 ,那么第一问的答案即 ,第二问的答案可以由 较小时的超重数之和,加上从 到 之间所有超重数得到。
因为对于固定的 ,所有 的 中有 个超重数(可表示为 ,其中 ),所以令 为 的最大的 (注意这个分割点 不应该取到比较靠近形如 其中 是一个很小的数的位置,因为这样会把 的超重数 分割成 和 两部分,无法直接用 乘以 的个数计算),答案加上 ,再枚举 的 ,若 说明 这一超重数的贡献也要算上,答案加 。
除去预处理的常数复杂度,时间复杂度为二分求 的 。代码预处理到了 ,此时 所以上式可改写为 。
第一个想法是若出现相邻的两个食物 满足 或 ,说明能够选择食物 的人一定会选择 值较大的那一个,因为就算有人和他抢食物他也能吃到热量较高的那个。
可能出现钦定一个人在 之间选择 后 又出现了一个数大于另一个数的两倍的情况,所以用队列进行 “松弛”。
松弛完毕后,对于没有钦定食物的所有人贪心地选择他相邻两个食物中热量较高的那个即可。若 选了食物 ,那么 就一定不会选食物 ,因为 。故两个没有钦定食物的人不可能选到同一食物,所以每个人的决策互不干扰,贪心正确性得以保证。
为防止出现小数的情况,可以在一开始将所有食物热量乘以 。注意此时判断 需要开 long long
。时间复杂度线性。
从上到下从左到右找到第一个需要被涂黑的地方,然后用印章从上到下从左到右第一个凸起对应该位置印一遍并实时更新所有需要被涂黑的地方(因为一个位置只能涂一次),需要预先存储所有凸起位置否则时间复杂度会炸。若有凸起对应的位置超出范围或不需要被涂黑则无解。时间复杂度 。
和联考之前考过的某一题基本上完全一样。每次贪心选最大的 个肯定没问题,但没办法直接模拟。
因为每个数之间顺序无关,此时一般通过将序列排序寻找性质:对于最大的元素 ,若 说明 必定能贡献 次取数,那么直接令 然后考虑剩下来 个数,这是一个子问题。递归边界是出现 ,这说明 都小于 ,此时每个 必定可以贡献满。现在问题转化为要求选 次,每次选 (这里的 实际上是询问的 减去 的数的个数)个不同的数,每个数被选择的次数不超过 其中 。
证明:看成一个 的表格,每一行的数互不相同且 的出现次数不超过 ,我们有如下方案:对于每个 有 次填数,每次选择最左边有空位的列的最上面那个位置填入 即可,即填数的轨迹是这样的:。因为对于轨迹上任意连续 个格子都有横坐标互不相同,所以符合条件。
因为对于轨迹上任意连续 个格子都有横坐标互不相同,所以符合条件。因此,只需判断是否有 即可。具体地,我们求出所有 的 的个数 ,以及所有小于 的数的和 ,若 则可行,否则不可行。这可以通过离散化 + 树状数组实现。时间复杂度线性对数。
类似求子区间个数的题目可考虑使用增量法。将这种思想运用到本题,考虑对于切在 的一刀从 挪到 的过程中合法的另一刀的位置 如何变化。
首先,当 时, 一定满足对于任意颜色 都有 要么包含所有颜色为 的珠子,要么不包含任意一个。也就是说对于每一种颜色,将所有出现的珠子看成一个环,那么合法的另一刀位置位于第一刀劈开的相邻两个珠子之间。
根据这一性质我们已经有了一个非常直接的做法:线段树维护区间最小值,数量,以及取到最小值的位置的最小值和最大值(这两个为了第二问),还需要支持区间修改。对于每个断点,找到没有被覆盖 “不合法线段” 的位置之和,即 等于 的位置个数。由于断点处一定没有被任何不合法线段覆盖,所以就是 取到区间最小值的位置数量 。第二问通过对应区间维护的最小值和最大值计算即可。时间复杂度线性对数,常数非常大。
运用题解区的哈希可以做到线性,而且常数很小。这个哈希维护本质相同区间套路在昨天 2021.12.18 的模拟赛中出现了。
裸的线段树优化建图板子吧。对于每个区间被选中的数 ,向区间 连边表示 大于这些区间中的任何数。若干个点向若干个区间两两连边可以建虚点优化 + 线段树区间连边。注意只有当指向的节点为叶子结点时有指向的点的值要小于当前点的值,否则只需满足不大于。时间复杂度线性对数。
求出现次数的题目可转化为求可能的出现位置数量,本题就运用了这一思想。我们定义小串 在 中的一次出现位置为 表示 。不难发现 的 是不合法的,因为它们超出了范围。
枚举每个字符 。若 说明 。这是一个不等式形式的限制, 同理。尽管在这样一个限制下 的解集可能不连续,但合法的 范围一定连续(在 意义下),因为 是一段区间,而 是常数。
同时,由于题目保证了 ,所以一个 解唯一对应一个 的解,所以我们只需求出合法的 个数,但要去掉不合法的 。
对于 个限制我们可以得到 个不等式,它的解集是在 意义下的一段区间,而所有解集的交除去所有不合法的 所得到的 后集合的大小即为所求。
注意求解集交不能直接对左端点取 ,对右端点取 ,因为我们是在 意义下求交(类似于环上区间求交),所以一个区间对应到 上可能会形成两段区间,这是无法处理的,只能通过离散化 + 差分求覆盖次数解决。
除掉不合法的 :将所有这样的 拎出来排个序,在(所有限制差分掉之后)求前缀和(后缀和也行,两种方法不同点在于如何用一个离散化的值 表示区间)的过程中用双指针扫一遍,表示落在当前离散化的值所表示区间的 范围(从而求得数量),就可以在计算答案时去掉这些数的贡献了。时间复杂度线性对数。
神仙思维题,暴力能过就离谱,建议去 BZOJ 上提交。
施工 ing ……
比较套路的根号分治题目。由于当步长 时最多走 步,所以我们设置一个阈值 ,表示若步长 则使用预处理的信息,若步长 则暴力树上倍增计算。
预处理的信息只需要 表示 每次向上跳 步能到达的所有节点权值之和,即 。可以在 的复杂度内求得。
综上,时间复杂度 ,当 取 时有理论最优复杂度 。如果用长链剖分求树上 级祖先则可做到严格 。
由于数据原因,实际表现中取 会很快。
区间 DP 好题。因为 具体值不重要,只关心相对大小,所以离散化 。设 表示区间 最小值不小于为 的答案。由于要输出方案所以记录 表示 的区间最小值取了 ,以及 表示 的分割点,这说明 由 和 转移而来。
转移枚举断点 ,则贡献为 ,其中 是满足 的 的个数,可以在枚举 的时候 预处理。注意还要和 取 。时间复杂度 。
考虑实时维护对于当前 所有连续 个数的和的最大值,前缀和 + 双指针 + 单调队列优化即可。 时往单调队列加入 ,不满足条件令 时若单调队列队首是 则弹出。时间复杂度线性。
提供一个被卡空间的做法:设 表示点集 的直径的两个端点,因为 ,而断掉一条边之后形成的子树 dfs 序连续,所以考虑倍增记录一段连续 dfs 序对应点集的直径端点。合并两个点集总共四个直径端点,只需要对这些点任意两两组合的六组点分别求树上距离,取距离最大的那组即可。
因此我们需要 求树上 LCA,考虑 RMQ 求解,时空复杂度即 。但因为我们开了过多倍增数组所以无法通过,只能获得 分的好成绩。
正解是换根 DP。断掉一条边 后 子树内的直径可以在最开始一遍 dfs 求出,因此考虑包含根的连通块的直径如何得到,设其长度为 。
若直径不经过 ,有两种情况:断掉 后包含根的连通块的直径即 ,或 除 以外的所有子节点的子树直径最大值。
若直径经过 ,也有两种情况: 的子树内最长的两条以 为一端且不经过 的链之和(通俗地说,就是 向下最长的不经过 的两条链),或 向下最长的不经过 的链加上经过 这条边且以 为一端的最长链(即 向上的最长链)。
综合一下,我们需要预处理出 向下最长的三条链 , 的所有儿子的子树最长的两个直径,并且在换根 DP 的过程中同时求出 向上的最长链(可以由 这条边与 向上的最长链或者 向下不经过 的最长链拼起来得到)。
求出断掉每一条边后形成的两个连通块的直径 和 后,显然最长直径为 和 相连,最短直径为 中点与 中点相连,从而求得新的直径的最大值和最小值,更新答案。
记录最大值和最小值分别由断掉哪一条边得到,最后再断掉这条边,暴力地对于两个连通块,分别对最大值求直径两端,对最小值求直径中点。时间复杂度线性,写起来比较麻烦。
非常显然的矩阵快速幂,由于边权只有 所以拆点,存储 和 表示以 结尾的长度为 的路径数量。最后再计一个 表示路径总数,得到转移矩阵 。预处理出 ,然后倍增求解即可。时间复杂度 ,有 倍常数。注意矩阵每个数在任何时候都要对 取 。
2016
根据取石子游戏的经典理论,我们需要选出 堆石子,使得 , 且这 堆石子的异或和等于 。
考虑设计 表示前 堆石子中选出 堆,异或和为 的方案数,直接做的复杂度是 ,因为不大于 的数最大可能异或出 ,无法接受。但注意到 有限制,说明有很多堆石子,石子数都很少。因为石子顺序不影响答案,如果我们按从小到大的顺序排列石子,那么前 堆石子能够异或得到的所有数均不超过不小于 的最小的 的幂 ,这样一来我们只需枚举到 而非 。总复杂度均摊下来就是 而非 。故可以通过,时间复杂度 ,空间复杂度使用滚动数组优化后为 。
2017
注意到当 时,,所以接下来只有 对答案有贡献,且依次是前 个数两两作差组合不出来的数从小到大排列的结果。预处理前 项两两差,每次询问二分即可。时间复杂度 。
2018
还算有意思的一道题目。对整个网格图求最小生成树。合并 的方案数即 。其中 表示该连通块当前的方案数, 表示当前高度, 表示该连通块当前高度,初始值为 。合并时实时更新 和 。时间复杂度线性对数。
2019
容易判断,对于 的,发现 ,所以预处理所有左端点 的区间的 的答案,用 map
存储。时间复杂度线性对数。
阴间模拟题。考虑求出使得 不同的第一个位置 ,有如下限制:
- 需要修改的位置数量不能超过 。
- 没有考虑到的位置数量不能小于还需要修改的位数。
具体地,对于每一位 ,求出 表示在第 位之前有多少 的位置。 合法的必要条件是 ,先判掉。由于上述限制要求修改位置数量既不能太小,也不能太大,所以需要考虑当前位是否修改:
- 若 ,说明可以不修改。此时若 且 则 合法。
- 若 或 ,说明可以 强制 修改(因为当 时不能修改)。此时若 且 则合法。
若找不到合法的 则无解。输出答案的过程时刻维护 表示还需要修改的位数:
- 若当前位 小于 ,输出 。
- 若当前位 等于 ,此时当 且 时输出 ,否则输出 ,前者因为这一位必须修改(否则将导致剩余位数小于要修改位数,不合法)。
- 若当前位 大于 ,此时当 且 时输出 ,否则输出 。
- 注意点:若输出的数码与 不同,则令 自减 。
- 注意点:任何时刻若 ,则输出 。
时间复杂度线性。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现