cnblogs。
Codeforces 编号在 1801-1825 之间的 Div.1,Div.2 only 和 EDU。
A. The Very Beautiful Blanket
尝试让每个 子矩形的异或和均为 。
显然,若矩阵 满足条件,则矩阵 也满足条件。
令 ,。为了最大化不同的数的数量,将 改成 即可。即 ,显然 互不相同。
时间复杂度 。代码。
B. Buying gifts
枚举取到 的 ,那么 不小于 。
除此以外, 且 的 可以任选,用 set 维护,查 在这样的 中的前驱后继。
按 从大到小排序后扫一遍。时间复杂度 。代码。
C. Music Festival
注意到重复播放一个专辑不会改变答案,且一个专辑只有严格前缀最大值有用。
设 表示以权值 结尾的答案。考虑专辑 ,那么 转移 。
前缀和优化,总转移数为 ,按 从小到大考虑所有转移即可。
离散化,时间复杂度 。代码。
D. The way home
关键性质:在城市 表演之后,不会在 的城市 表演。
设 表示到达城市 最少需表演多少次, 表示对应剩余钱数。以 为第一关键字从小到大, 为第二关键字从大到小,按 从小到大的顺序转移即可。
说明:对于两组贡献 和 ,不妨设 ,若 ,说明对于 对应的方案,一定可以少表演几次使得 变成 ,但 仍大于 :在 之前表演的城市的 值小于 。
跑 遍 Dijkstra 求出任意两点之间的最短路。时间复杂度 。代码。
E. Gasoline prices
假设树是一条链,考虑求出第一个位置,使得两条路径该位置的点的代表元不同。BIT 维护哈希套二分,修改就启发式合并,在 BIT 上对应更新。
搬到树上就套个树剖即可。注意二分前将每段重链的哈希值先算好,保证单次检查只要查一段区间的哈希值。注意还要维护逆序哈希。
时间复杂度 。代码。
F. Another n-dimensional chocolate bar
将答案除掉 ,设 表示切成 块的最大答案,发现 相同的 等价。
设 表示至少还要将数量乘以 的最大答案,初始值 ,转移枚举每个 ,再枚举使得 相同的 ,用 更新 。答案即 。
因为 ,所以算法正确。
时间复杂度类似杜教筛分析,为 。代码。
*G. A task for substrings
设 表示 的后缀有多少个是单词, 表示最长的为 的后缀的单词编号, 表示 的前缀和。
对于每组询问,直接用 回答询问,相当于求出了右端点在 的子串单词数量,但没有保证左端点在 范围内。
考虑找到最大的 使得 ,那么以 为右端点的合法子串单词数量就等于 ,以 为右端点的合法子串数量就等于 的长度为 的后缀有多少个子串是单词。
设 表示编号为 的单词的长度为 的后缀有多少个子串是单词,总状态数 ,建反串 ACAM 预处理。
建正串 ACAM 预处理,线段树二分求 。
时间复杂度 。不难看出算法是 在线 的。代码。
A. Lame King
令 , 不改变答案。
当 时,答案显然为 。
否则不妨设 ,那么最优策略是:向上向右交替走到 ,然后停一次,向上走一步。答案为 。
B. Vaccination
考虑若干人可以打一包疫苗的充要条件:来得最早的人和来得最迟的人的时刻相差不超过 ,且总人数不超过 。直接按时间顺序贪心即可。
时间复杂度 。代码。
C. Pull Your Luck
注意到 ,所以令 即可。
时间复杂度 。代码。
D. Accommodation
每一行独立,对每一行分别做。
设开灯总数为 ,两个灯都开的双人房数量为 ,那么被占用的房间数为 。
最小化被占用的房间总数,等价于最大化 。直接贪,扫一遍,能放就放。证明一定合法:不超过 个双人间将序列割成了不超过 段,每段都可以用至多一个单人间调整奇偶性。
最大化被占用的房间总数,等价于最小化 。类似地,扫一遍,能放(至少一个灯没开)就放。
时间复杂度 。代码。
E. Routing
连边 ,得到基环森林。每棵基环树的环上所有点的邻居必须为全集,否则从环上的点出发,存在无法到达的点。
考虑一个邻居为全集的环,从环上每个点出发 DFS 剩下的点,记录每个点的父亲,得到一组合法方案。
问题转化为找到邻居为全集的环。枚举起点,设 表示从起点出发经过 最终能到达哪些点,转移即枚举 ,找到后也容易构造方案。
时间复杂度 。代码。
钦定起点为编号最小的点即可做到 。代码。
*F. Approximate Diameter
很优雅的暴力。
首先,因为 ,所以 。至此可以做到 。
上述做法没有用到答案可以在 ,想要用也很简单,假设 求出的答案为 ,那么对于 的 ,输出 也合法。又因为 单调不增,所以每次二分出最后一个使得 的 ,将 均赋为 。
因为每次二分答案至少减半,所以总复杂度 。代码。
直接分治复杂度是一样的,边界条件 。代码。
*G. Flow Control
除以 下取整,很难让人不想到自然 。
先假设没有插入和删除,那么每次被挤爆会导致序列极差变成原来的一半,在 次挤爆之后就变成了会循环的平凡情况:所有数全部相同,或者除以 下取整之前分别是 和 。
考虑用 set 维护值域连续段,剩下来就是暴力模拟了。
一个细节:删除时需要知道删除的数的值,对 set 每个元素额外维护对应下标,每次修改时更新下标对应的值,注意涉及到合并要用并查集。或者直接把 set 改成线段树,区间不全相同就递归下去修改,势能分析得到同样的复杂度。
时间复杂度 。细节有点多。代码。
将 set 换成哈希表即可做到 。
*H. Code Lock
很厉害的题目。
设 表示 在密码串中相邻出现了多少次,那么问题相当于求排列 最小化
如果按顺序 DP,要记录 的顺序,那就彻底寄了:无论如何都无法避免 。只能换一种 DP 方式了。
设 ,将贡献拆到每个点上,分成 和 讨论。钦定当 时 取 ,否则 取 。
对于 ,有
对于 ,有
首先枚举 。
对于 ,需要知道 和 中的任意一个,以及 和 中的任意一个。
对于 ,需要知道 和 中的任意一个,以及 和 中的任意一个。
发现如果按照 的顺序加入元素,只要维护已经加入的元素集合 ,就可以计算 。状态数为 。还要乘以枚举 的 。
状态数有点多,不妨钦定 ,这样是 ,再乘以枚举下一个位置的复杂度,可以接受。
代码。
A. We Need the Zero
对于 ,要求 异或和为 ,输出任意数。
对于 ,输出 异或和。
B. The String Has a Target
对于 a
到 z
的每个字符,一定是将最后一次出现移到最前面,模拟即可。
时间复杂度 。代码。
只要将最小的字符的最后一次出现移到最前面就行了!我是憨憨。
C. Place for a Selfie
考虑无交点的充要条件: 无解,即 ,即 。
用 set
维护斜率查前驱后继即可。注意边界处的处理。
时间复杂度 。代码。
D. A Wide, Wide Graph
如果一个点和其它点有连边,那它一定和直径的某一端有连边。
求出每个点到直径两端的距离最大值 。对于 ,这个点一定是孤立点。对于 ,这个点一定和直径一端相连,而直径两端相连,所以所有 的 形成一个连通块。
因此,对于 ,答案为 的 的数量加 。对于 ,答案显然为 。
时间复杂度 。代码。
E. There Should Be a Lot of Maximums
dsu on tree 并用两个 set 分别维护子树内和子树外所有 的数。可以做任意 。
时间复杂度 。代码。
另解:对于 的数,一定产生贡献。对于 的数,一定不产生贡献。对于 的数,只有一条链不产生贡献。找到最大的 的数,这条链以外的边的答案好算,对于这条链只需以两端分别为根 DFS 即可。时间复杂度可做到除离散化外 。
另解:DFS 序拍平并复制一份,相当于区间查询 的最大值。将所有询问离线下来后扫描线,用权值线段树维护每个数倒数第 次出现的位置,查询在线段树上二分。可以做任意 。时间复杂度 。
*F2. Survival of the Weakest (hard version)
好题。
首先钦定 不降,考虑 F1 的 怎么做。
值域太大肯定不能直接模拟,那就想办法减小值域,可以想到维护值 和序列 表示 ,其中 为 。比较 和 时,只要比较 和 。注意到一次操作后新的 和 相差不超过 ( 可以贡献前 小值),所以新的 不大于原来的 。值域不会增大,可行。
每次将 变为 即 (),然后模拟即可。模拟就是经典超级钢琴,根据 的单调性直接双指针 + 优先队列维护,不用可持久化线段树。
歪解:
首先有个猜测是 会在很短的时间内缩减为 ,这是错的:,每次将 减去 , 变成 。这组数据启发我们得到算法:如果 ,那么将 全部减去 , 变成 。全部减去的过程直接打标记即可。这也是错的:代码。
为什么会错呢?仔细思考,我们发现将 全部减去 只有在 的时候合理,所以判断当 的时候再执行该操作。然而还是 TLE。打个表( 很小, 很大)发现 的收敛速度不尽如人意:考虑 ,每次操作会 减去 ,然后将 ( 等于操作编号加 )再减去 (来自 和 的贡献),这要收敛到猴年马月去了。
我们充分发挥人类智慧:猜测编号较大的位置没有用,将判断条件改成 ,其中 是一个比较小的数。这样就可以 通过 了,但不知道为啥对。
疑点:将 改成 还是可以 通过,但不知道为啥对。
知道上述两个做法为啥对或者有 hack 数据可以教育一下(如何保证正确性和复杂度)。
感觉告诉我们较大的元素是没有用的:它们会在之后的操作被 “弹出”。弹出即新的序列没有和该元素有关的和。如果 没有被弹出,那么 。操作后得到序列 。发现再操作一次,序列末尾的数不大于 。
注意到 ,即 。这说明如果存在一次操作没有弹出 ,那么 在第二次操作之后至少减半。
发现上述结论对任何 都成立:若 ,那么 在第二次操作之后至少减半。这给予我们只保留前 个元素的想法。
证明:对于一次操作:
- 若 ,那么由 可以确定新的正确的 。
- 若 ,那么至少新的 是对的。再操作一次,至少新的 是对的,且 。不妨令 减去 。
因为情况二最多发生 次(当 变成 时,,不可能发生情况二),使得 减去 ,而 ,所以一定能求出正确的 ,算法正确。
因此,只保留序列 的前 个元素,每次仅根据 求出新的 (注意这不改变序列长度),模拟操作 次,则 即为所求。
需要特判 。
时间复杂度 。代码。
A. Walking Master
每次向右上或向下走 单位,于是对坐标轴进行剪切变换,即令 ,那么每次令第一维或第二维加 。
检查是否有 且 即可,答案即 。
B. Mex Master
如果 ,那么可以在所有奇数位置上放 ,分数为 。
否则若序列只有 ,那么分数为 。
否则可以用非 正整数隔开 和 ,分数为 。
时间复杂度 。代码。
C. Sequence Master
假设所有数相同,有 或 或 的平凡解。
接下来不妨设 ,令 ,根据 和 的条件可得方程 ,那么 。
又因为所有 且 ,均有 ,得 相等。
所以当 为偶数时,没有其它解。当 为奇数时,。接下来容易推出 ,,因此序列中恰有一个 ,其它元素为 ,贡献为 。
时间复杂度 。代码。
*D. DSU Master
好题。
考虑一个 产生贡献的充要条件: 中出现了 所有元素,且此时 没有出边。
设 表示 的答案,考虑递推:将值 插入所有 阶排列。
性质:只要不将 插到最后,那么它一定不产生贡献。显然。
性质:将 插到任何位置不对已经产生的贡献产生影响。证明:因为 对应的操作一定不会涉及到包含 的连通块,所以不会打破其它产生贡献的元素的产生贡献的条件。
如果将 插到最后,那么它产生贡献当且仅当前 次操作后 没有出边。因此,设 表示 时操作后 没有出边的排列,则 ,且 , 且 。
时间复杂度 。代码。
*E. Tree Master
这题也挺不错,考察了对根号分治的理解。
记忆化后直接暴力就是对的:设 表示深度为 的结点数量,对于所有 ,总共只有 对点。对于每层 ,每个询问只会涉及到一对点,因为这样的层数不超过 ,所以总共只有不超过 对点。
使用 map 或 unordered_map 会 TLE,手写哈希表即可通过。
时间复杂度 。代码。
*F2. GCD Master (hard version)
很好的猜性质题目。
对最终序列的每个元素 ,用集合 描述它是由原序列哪些元素求 得到的。考虑两个大小不小于 的 ,不妨设 。我们将 中最大的元素 单独拎出来,其它元素并到 里面去,发现这样做产生 。注意 且 ,如果 ,那么 。那么不妨设 互不相同,就满足条件了。得到结论:若 互不相同,那么恰好存在一个 ,其它 。
存在相同的元素怎么办呢?注意到将相同的元素合并一定不劣,所以如果去重之后的 消耗了 步操作,那么还要操作 次。将多余元素从小到大排序取前 个求和,从总和中减去即可。问题转化为对去重后的 求每个 的答案。
枚举 的 ,然后从小到大枚举它的所有倍数 ,属于 的一定是一段前缀。设当前考虑了 个元素,总和为 ,若 ,那么还需要 次删去相同元素的操作。时间复杂度 , 因子可以去掉,可通过 F1。代码。
观察:操作 之后,总和至少减去 ,自然想到不要操作特别大的数。将 排序后,不妨先取 ,然后调整。
设原 为 ,那么代价为 。调整的核心在于,将 变大一些,然后让 变得大很多。注意到 不大于任何两个相邻元素的差,所以调整超过一个元素是不优的:假设 被选中,其中 ,那么 至少大了 ,但新的 ,不优。
进一步地,可以证明调整 一定不优,其中 :设 调整为 ,其中 ,发现 增加 ,但新的 ,不优。
因此,设 ,问题转化为求 。
又因为 ,所以随着 增大, 只会改变 次,每次增大后重新求 的后缀最大值即可。总时间复杂度 。
很显然, 的计算可以均摊。记录 ,每次 改变时令 ,势能分析过程的总复杂度是 。
总时间复杂度 。注意使用 __int128
,代码。
A. Lucky Numbers
从 到 枚举,如果找到幸运值为 的直接输出。
因为枚举 个数之后一定存在以 结尾的数,所以每次不会枚举超过 个数。
B. Playing in a Casino
考虑所有卡片上第 个数的贡献。设它们形成长为 的序列 ,将 从小到大排序,那么 和 产生总和为 的贡献,和 产生总和为 的贡献。
时间复杂度 。代码。
C. Unlucky Numbers
数位 DP,设 表示还剩 位没有考虑,已经填的数码最小值为 ,最大值为 ,是否顶到 的下界和是否顶到 的上界时,已经填的数码形成的数或无解。转移即枚举下一位数码 ,先判是否合法,若合法则求出新的 ,将 赋值为 。注意判还没有填任何数码的情况。
时间复杂度 ,其中 表示进制数。代码。
一个值得借鉴的思路:将 拆成若干 ,满足 。每个区间的答案显然为 。
D. Petya, Petya, Petr, and Palindromes
不妨先认为答案是 ,再减去可以减小答案的下标二元组 的数量,满足:
其中第四个和第五个限制容易漏:有些位置是无法成为回文中心。
对于所有值相同的下标序列 ,枚举 ,用三个指针分别维护第三、四、五个条件对应的 的边界。注意根据 的方向确定指针的初始位置和方向。
第三、五个条件限制了 的最大值,第一、四个条件限制了 的最小值。求出边界后,查询 的一段区间上有多少个奇数,或查询有多少个偶数,前缀和维护。
时间复杂度 。代码。
E3. Minibuses on Venus (hard version)
一
设 ,不存在 。
补集转化,枚举 ,设 表示长度为 且总和为 的非法序列,转移即枚举 ,。
对每个 的 求和,再用 减掉,即为答案。
时间复杂度 ,可以通过 E1。代码。
二
先把 判掉。
当 时,对每个 ,存在恰好一个 使得 ,即 。将 减去 ,问题转化为:求 且包含 的序列数量。补集转化,套用 E1 的 DP,可知对于 , 相等。有递推式 ,。矩阵快速幂求出 ,再根据 是否为 的倍数计算答案。
当 时,对每个 ,若 ,则所有序列均不合法,否则恰存在两个 使得 ,记为 和 ,则 ,。将 减去 ,问题转化为:求 且包含 或 的序列数量。补集转化,套用 E1 的 DP,可知对于 ,,且对于所有 , 相等。有递推式 ,。注意该递推式对于 不成立。同样可以矩阵快速幂解决。
时间复杂度 。代码。
三
对于 ,瓶颈在于计算 的 的数量。因为 且 和 一一对应,所以相当于计算 的 的数量。典中典, 必须是 的倍数,在 里面恰有 个。
对于 ,瓶颈在于计算 或 的 的数量,即 。因为 且 和 一一对应,所以相当于计算 的 的数量。因为 ,所以类似地, 的数量为 。
时间复杂度 。注意特判 。代码。
四
对于 ,打表观察发现对于偶数 有 ,对于奇数 有 ,即 ,容易归纳证明。由此可知 ,即 ,共乘以 个 ,其中 。将括号拆开,发现就是 ,变形得 ,等比数列求和得 ,即 。设 ,推式子:
因此对于 ,答案为 。
对于 ,打表观察发现有 。一个感性理解: 的 DP 相当于两个规模为 的 的 DP(注意不是分成两个子问题,只是借用 DP 转移方式),而两个 DP 之间是对称的,产生双倍贡献。类似地,得到递推式 。对比它和 的 DP 递推式 ,结合之前的感性理解,即做规模为 的 的 DP 且每次系数翻倍,考虑设 ,得 。对于 类似,有 。所以,先做规模为 的 的 DP 得到 ,然后根据 反推出 :仅仅是将答案乘以 。设 ,:
因此对于 ,答案为 。
时间复杂度 ,但是封闭形式。代码。
五
不觉得打表找规律有点不牛吗?
设 表示 个 之间的数之和为 的倍数的方案数,则 。
考虑任意填 ,最后用 补成 的倍数。发现当且仅当 时不合法,得到递推式 。注意边界 ,这直接说明 。
对于 ,推导是类似的。
六
除了上述做法外,还存在根据 “不能放 ……” 的限制二项式反演 + 推式子的做法。不过该做法比较平凡,就不赘述了。
A. Garland
当 时,答案为 。
当 时,答案为 。
当 时,显然无解。
B. Points on Plane
二分答案,考虑 是否有解。
取遍所有 和 奇偶性相同的 ,形成若干边长为 的小正方形,总共可以选择 个点。
因此,答案即最小的 使得 。
C. Sum on Subarrays
设前缀和数组为 ,初始令 。
每将一个 变为 ,都会增加 个和为正数的子序列。从后往前贪心即可。
时间复杂度 。代码。
D. Binary String Sorting
可以证明最多交换一次。
枚举 分界线,求出要删除几次,再检查是否可以用交换减小代价。
时间复杂度 。代码。
E. Two Tanks
注意到 不变。枚举 ,则用第一个水箱的水量即可描述状态。
考虑对所有 求答案。
对于两个初始状态 ,如果任意时刻它们的值相同,则它们的答案相同。导致值相同的原因就是两个水箱满了或空了。
显然,当 很小或 很大的时候,这种情况越容易发生。而如果这种情况没有发生,则最终的 就等于初始的 减去 。
因此,答案形如 ,直接二分的时间复杂度为 。代码。
设 表示 的答案相同, 表示 的答案相同,依次考虑每个操作并更新 ,时间复杂度 。
F. Traveling in Berland
因为油价只有 或 ,所以遇到 ,我们一定能加满就加满,实在没油才会加 。
不妨钦定到每个 时油箱恰好为空。如果不为空,则当前油箱里的油的单价不小于 ,替换为当前城市的油不劣。
考虑从城市 出发到另一个城市 的代价 ,满足中途没有 ,且出发前和到达后油箱均为空。设距离为 。当出发城市油价为 时,代价为 。当出发城市油价为 时,若 ,代价为 ,否则代价为 。
破环成链,考虑 中途的所有油价为 的城市 ,则 即为所求。
倍增,设 表示从 出发跳 步(每一步跳到下一个 )到达的城市及对应代价。时间复杂度 。代码。
因为出发城市和到达城市单调增,所以双指针维护可做到 。
*G. Prediction
考虑符合要求的 的排列 ,两个选手比赛时评级较高的选手胜出。因此,题目中的条件等价于:对任意 ,。
因为 和 一定会比赛,所以当 时,无解,答案为 。
设 表示最大的 使得 , 表示最小的 使得 。
考虑钦定前缀最大值的位置 计算对应排列方案数。对于 ,位置大于 的 必须放在 之后。从限制强到限制弱依次插入每个元素。
- 对于 ,将 不含 的所有位置放在 之后,方案数为 。
- 从 到 枚举 ,注意到 (否则不合法),所以相当于将 不含 的所有位置 放在 之后,此时 不含 的所有位置已经在 之后。因此,考虑每个位置插在哪个元素后面,方案数为 的积。
- 最后将 放在 之后,方案数为 的积。
- 整理,得方案数 。
设 表示 的方案数之和,从后往前转移,前缀和优化即可。
时间复杂度 。代码。
A. Beautiful Sequence
检查是否存在 即可。
B. Candies
如果 是偶数显然无解。否则考虑倒推,恰有一个操作使得操作前也为奇数。
总操作次数 。代码。
C. Make It Permutation
特判掉全删掉再加一个 的情况,最终排列长度一定是某个 ,调整法易证。
排序后枚举 ,容易算出需要删掉和加入多少个数。
时间复杂度 。代码。
D. Climbing the Tree
令 ,即每天相对于前一天上升的距离。
根据 可以算出树高区间 。特别地,当 时区间为 。
维护当前树高区间 ,加入一个区间时,若有交,则将 变成它和加入区间的交,否则一定不合法。
查询即检查 和 的答案是否相同,若相同则输出,不相同则无法确定。
时间复杂度 。代码。
E. Monsters
考虑从 的点开始 BFS,维护每个连通块。每次从队列中取出一个连通块,按 从小到大的顺序枚举所有出边,若已连通则跳过,否则能合并则合并(即当前连通块大小不小于对应 值),不能合并说明接下来也不能合并,直接退出。若整个过程至少合并一次,则重新丢入队列。
启发式合并 set
维护当前连通块的所有出边,时间复杂度 。代码。
F. M-tree
考虑求一次答案。假设答案为 ,维护 表示能接多少个叶子,初始值为 。从 枚举到 ,每次先将 乘以 ,然后减去等于当前枚举值的 的数量。若最终 则答案大于 ,否则答案不大于 。
在 进制下观察整个过程,我们发现相当于求最小的 使得 。用线段树或 set(维护值相同的连续段)维护 形成的 进制数即可。
时间复杂度 或 。代码。
G. The Maximum Prefix
直接正着推肯定不太行,因为枚举 再枚举 已经要 ,再加上 DP 时肯定要记录当前前缀和,肯定寄了。
那么唯一的办法就是将 直接融入 DP 值,也就是直接 DP 期望值。那我们在一开始肯定得区分不同的 ,这就给予我们唯一的 DP 设计方案:设 表示当前序列长度为 ,还需要加上 才能达到 ,以及是否达到过 。转移即 以及对于 ,。 的答案即 。
时间复杂度 。代码。
*H. Last Number
找点规律。
打表发现问题分成两部分:第一部分的 ,第二部分的 等于上次操作的结果。设 为第一次 的操作,那么 为第一部分, 为第二部分。
设 表示第 次操作的 , 表示 ,,答案即 。因为 ,所以只要求 ,这要求我们用优秀的方式描述 。
在操作 的部分, 递增,且 不降,所以一个数最多只会加入 一次。注意到第 次操作后所有 的数不会再改变,设这些数为 。考虑随着 增大 的变化情况:
- 若 ,相当于往 中加了两个 。
- 若 ,相当于往 中加了两个 和一个 。
设 ,那么 相当于在 末尾加入 , 相当于在 末尾加入 。
不断进行操作,得到无限长度的字符串 形如 0 / 10 / 110, 10 / 110, 110, 10, 110, 10 / ...
,其中每一层都是上一层的字符串的 0
变成 10
,1
变成 110
,然后拼接而成。设 表示 的前缀和,那么 。
考虑答案式 。
- 当 是偶数时,答案为 。
- 当 是奇数时,答案为 。
问题转化为:给定前缀长度 ,求 的前缀和,前缀奇数位置和,前缀偶数位置和。设 表示从 开始迭代 次,得到的字符串的长度,和,偶数位置和,奇数位置和。按顺序合并两个四元组 和 时:
- 。
- 。
- 当 为偶数时,,否则 。
- 当 为偶数时,,否则 。
预处理这些信息后容易做到单次查询 。
二分求出 ,容易通过 次查询求出答案。时间复杂度 。
可以类似查询的方式做到 计算。时间复杂度 。代码。
实际上 就是斐波那契串,那么 。将 用分数近似表示后转化为经典和式:使用类欧几里得算法求解。
G2. Vlad and the Nice Paths (hard version)
设 表示以 结尾的最长合法路径长度, 表示对应方案数。
枚举 ,要求 至少出现 次 ,用 更新 。
对所有 ,设 在 中出现 次,将 加上 。
时间复杂度 。代码。
A. Coins
若 ,那么将 减去 , 加上 一定合法。
检查 和 是否有解即可。
B. Long Legs
考虑枚举操作 的次数 ,那么总操作次数为 。
显然 不超过 ,直接枚举即可。
时间复杂度 。代码。
C. Search in Parallel
考虑若将 放在第 个机器人的序列的第 个位置,会产生代价 。按 从大到小,每次将其贪心插到代价最小的机器人序列中,即 和 的较小值的对应序列。
时间复杂度 。代码。
*D. Balancing Weapons
若所有武器均被调整,则总存在方案:令 即可。
否则至少一个武器被保留。直接枚举保留的武器 ,那么其它武器 只有三种可能:
- 保留,代价为 。
- 改成最大的 使得 ,代价为 。
- 改成最小的 使得 ,代价为 。
注意修改后的 必须大于 ,所以一些情况是非法的。
总共 把武器,按 排序后双指针。若当前 之间所有原武器均出现,那么可用区间内只出现代价为 的武器的原武器的数量更新答案。
时间复杂度 ,和 无关。代码。
利用 较小的性质容易做到 :只有 的新武器有用,直接桶排即可。
E. Chain Chips
考虑到总可以调整使得一条边被经过两次,且与一个点相邻的两条边至少有一条要被经过两次,设 表示考虑到第 条边, 是否被选择的最小代价,有 ,。动态 DP 即可。
注意第一条边和最后一条边一定要被选。
时间复杂度 。代码。
F. Communication Towers
考虑线段树分治,到每个叶子 时,所有与 连通的信号站都可以收到信号。
合并 时,若 均不包含 ,那么新建点 连向 。若 包含 ,则将 打上标记。若 包含 ,则将 打上标记。最后从有标记的点开始可达的所有信号站就是答案。
时间复杂度 。代码。
A. Ian and Array Sorting
做一次差分 ,那么操作相当于将 ()加上任意整数 , 减去 。目标序列满足 , 和 可以任取。
因为所有偶数位置上的 和所有奇数位置上的 总和分别不变,所以若 为偶数,那么一定可以达到目标,若 为奇数,那么可行当且仅当 。
时间复杂度 。代码。
B. Sum Graph
加入所有 和 的边,得到一条链。
任选一个 ,得到 和所有 的距离 ,然后任选一个 的 ,得到 和所有 的距离 。对于 的 ,和 在同一侧,否则在另一侧。根据得到的链,只有两种可能的排列,回答之。
总询问次数恰为 。代码。
C. Between
对限制 ,从 向 连有向边。对于所有有向边 ,若整个序列有 个 ,那至多能有 个 。
考虑 到每个点的最短路 ,若 不可达 ,说明 的出现次数可以为无穷大。否则 至多出现 次。
构造答案:从 到 枚举出现次数 ,从 到 枚举每个点 ,若 ,则将 加入序列。
时间复杂度 。代码。
D. XOR Counting
是平凡的。
可以构造 ()和两个 做到任意 ()。
相当于求 的所有可能的值之和。
数位 DP 记录一维表示下一位是否进位,枚举 和 的第 位,根据实际意义转移即可。
时间复杂度 。代码。
*E. Bosco and Particle
很厉害的一道题目。
首先将每个串变成它的最小整周期串,那么就是要计算经过多长时间后,粒子再次回到 且所有对撞器的指针指向开头。
对于每个对撞器,其指针所跳过的 的数量决定了粒子的位置:若为偶数则在左侧,为奇数则在右侧。所以若串中 的数量为奇数,则需要倍长该串。
对每个对撞器,求出信息:每 次从左侧进入,将产生 次向右侧出发,其中 表示第 个 到第 个 之间的字符数量, 表示第 个 到第 个 之间的字符数量。
考虑从 出发的次数 ,则 均需要是整数。对所有 分解质因数,容易得到最小的 ,进而得到循环节长度。
注意特判全 串,此时将其视为 即可。
时间复杂度 。代码。
*F. OH NO1 (-2-3-4)
神必 MO 题。
设 表示 加上 的入度,考虑给每条边定向使得 互不相同。每次取出 最小的 ,将与之相连的还没有定向的边指向对应邻居,这样未处理的点的 只会增大,符合限制。
每个三元环的贡献形如 或 ,而在原问题上对三元环构造 和 是容易的。因此,将每个三元环上所有点的 加上 ,然后做转化后的问题即可。
时间复杂度 。代码。
A. Almost Increasing Subsequence
答案为区间内属于某个长度大于 的上升子段的位置数量。若左端点不属于这样的位置,答案还要 ,右端点同理。
时间复杂度 。代码。
*B. Fish Graph
枚举 ,显然 的度数不小于 。如果我们找到了经过 的环,考虑环上与 相邻两点 ,加入 的两条非 出边 。
且慢,万一 也在环上怎么办?调整成环 ,然后加入 和 即可。
如何找经过 的环?这就是套路的积累了。
从 的所有出边开始 BFS,记录每个点是由哪个 的邻居达到的,设为 。BFS 时,若遇到边 满足 ,则存在环 。为输出方案,记录每个点在 BFS 树上的父亲 。
然后我们发现,因为执行的是 BFS,所以找到的环的长度一定最小,也就是说,对于一开始的思路, 不可能在环上,皆大欢喜。
时间复杂度 。代码。
直接找一个点双里的 即可做到 。
*C. Similar Polynomials
多项式次数太高了,不好处理。考虑 “求导” 降次。离散意义下就是差分。
我们知道,对函数做形如 的差分,则 。所以将 个点值差分 次, 从 次变成 次,也就是直线 。
的 阶差分 分别等于 ,相当于 在 和 处的点值。
即 的 阶差分 分别等于 ,相当于 在 和 处的点值。
显然,根据 和 可以直接确定直线,再代入 或 即可。答案即 或 。
至于 阶差分怎么求:
时间复杂度 。代码。
D. Toy Machine
烂烂 烂烂 烂烂 烂烂 烂烂 烂烂 烂烂 烂烂 烂烂 烂烂。
烂烂 Ad-hoc。
对于 ,考虑把 搞到它后面,容易想到执行 LDRU
,发现 向前移动了一位。因此,设 ,对于 ,执行 次 LDRU
和一次 L
。
那后半部分怎么办?考虑先用对称的方法将 挪到最右边,然后不断执行 RDRU
直到所有数全部堆在右半部分,且 在右上角,再执行一次 LU
, 就变到了原来 的位置。
时间复杂度 。代码。
*E. Half-sum
不妨设 ,则一组方案的权值为 。
考虑最终变成 和 的所有数 和 (),从小到大排序。设 被合并 次, 被合并 次,则 等于
观察样例 ,发现 是 ,,, 这样得来的,这启发我们猜想:对于 ,一定是先合并 得到 ,再合并 得到 ,以此类推。对于 ,一定是先合并 得到 ,再合并 得到 ,以此类推。
证明:
对于四个数 ,不妨设它们属于 ,那么合并 ,再将得到的数合并 ,再将得到的数合并 ,一定不劣于将 分成两组,两两合并后再合并。对于前者,贡献为 ,对于后者,贡献为 。因为 ,所以 。这说明: 不会由 和 合并而来()。
因此 形成的可重集形如 ,将较小的 分给较大的 一定更优。调整法易证。
综上,,对于 ,。
对于 ,同理。
有了该结论,若存在 ,则交换 更优,因为减数变小了,加数变大了。
这说明将 排序后存在 使得 合并至 , 合并至 。
至此可以做到 :枚举 ,计算 ,用二进制高精度表示,形如 。求出 的最大值。
遇到这种 的幂的情况,通常都会根据 的幂的性质(),将某些范围限定在 值域的大小(数位 DP 经常用到这一点)。
考虑 ,把式子写下来发现 。这说明对于 的 ,,,即若 ,那么在 之间切一刀一定不优。除非所有数相等,此时答案为 。
进一步探索,对 差分得到 (),对于 ,有
当 时, 的系数是负数。如果 ,那么 , 一定不优。因为 且 ,所以只要 且 ,就有 。
因此,找到第一个使得 且 的 , 在前半部分一定更优。若不存在,检查 。对于右半部分同理。
一个等价的实现是:找到前 和后 个 的位置,检查之。
时间复杂度 。代码。
官方题解给出了妙妙分治做法:在 寻找最优决策点时, 和 的系数不变,只关心 ,可以做到 比较左子区间和右子区间哪个更优。时间复杂度 。将该思想应用于上述做法,可得 解法,但读入信息量为 。
F. Entangled Substrings
建出基本子串结构, 合法当且仅当它们不重叠且属于相同等价类。
问题相当于求一个左边界和上边界对齐阶梯型内有多少点对 满足 。枚举 ,用单指针求出有多少 ,使得 的 数量也容易前缀和求出。
时间复杂度 。代码。
A. Constructive Problem
求出 ,若 显然无解。
否则,若 ,显然有解。
否则 一定要包含 的所有出现。感性理解区间越小越好,所以将 赋值为 ,检查是否有 即可。
时间复杂度 。代码。
B. The Butcher
考虑逆推。
先算出面积 以及 和 。那么形状只有可能是 或 。
检查 是否为答案是容易的:每次必然切掉一边,按 和 分别从大到小排序后用两个指针维护即可。
时间复杂度 。代码。
C. The Fox and the Complete Tree Traversal
先把 的平凡情况特判掉,否则选一个非叶子作为根。
对点 ,考虑环在 子树内的部分,发现必然是一段,因为进去再出来再进去再出来是不可能的。因此,设 子树的插头为 ,其中必然有一个是 ,另一个是 的儿子,设为 。当 为叶子时 不存在。
合并 的所有儿子时,若 有两个儿子 非空,因为 只能跳到 ,所以当且仅当 为根时合法:若 非根,因为根不是叶子,所以则 子树外必然有一个距离 为 的插头,这个插头只能跳到 。
对于非叶子:
- 若所有儿子 为空,则连接 和任意儿子,并将剩下所有儿子串起来,令 为最后一个儿子。
- 若存在一个儿子 非空,则从该儿子开始将剩下所有儿子串起来,令 为最后一个儿子。
- 若存在两个儿子 非空,若非根则无解,否则从其中一个儿子开始,另一个儿子结束将所有儿子串起来。
- 若存在大于两个儿子 非空,无解。
- 特别地,将所有 非空的儿子的 和 直接相连。
最终得到以根为端点的链或一条环。从根开始在环上遍历即可。
细节较多。时间复杂度 。代码。
实际上,一棵树合法当且仅当它是毛毛虫,将度数为 的点处理掉,剩下一条链,处理一下即可。
D. Misha and Apples
将商店卖的苹果种类看成集合 ,设 表示最小的 使得编号为 的集合都可以被保留。
考虑转移,显然 。
- 若 ,则令 即可使 。
- 若 ,考虑最大的 使得 和 有交。若不存在,则 。否则若此时 仍未被删去,则整个背包就空了。
- 若 , 无论如何一定被删去,。
- 若 就不太好办了。发现此时 等于最小的 ,满足 且存在一种方案使得 之后整个背包为空。
因此,设 表示是否存在一种方案使得处理 之后整个背包为空。
- 若 ,总可以使得背包为空:若处理 之前背包为空,则令 ;否则令 为之前的背包。故 。
- 若 ,如果 之间有 ,则可以通过合理地设置 清空背包,。否则考虑最大的 使得 和 有交。若不存在,显然 。
- 若 ,则无论如何 无法被删去,。
- 若 ,则 可以通过 将整个背包清空,。
用 set
维护所有 的 ,时间复杂度 。
每次查询 lower_bound
之后 值变成对应后继加 ,具有单调性,直接双端队列维护。
若 之间有 ,显然答案为 。否则答案为之间的 之和。
时间复杂度 。注意清空的复杂度,因为 没有保证。代码。
*E. Roads in E City
考虑删边,删去 后随机询问 次 或 ,若 不连通,则有极大概率得到至少一个 。否则所有询问均返回 。由此求出任意一棵被修复的边的生成树。
接下来考虑每条非树边 ,删去 树上简单路径上任意一条边 ,然后加入 ,随机询问 次 或 ,可以以极大概率求出 是否被修复。原理是一样的。
正确率为 ,其中 。代码
*F. Willy-nilly, Crack, Into Release!
变换规则太复杂了,但是有一点很显然:若 经过一次变换得到 , 也可以经过一次变换得到 。
这启发我们把所有字符串以及它们之间通过单次变换互相转化的关系抽象成图,然后研究图具有的性质,因为在图上更容易看出一些仅通过字符串和复杂的变换难以发现的性质和模式。从这点来看,抽象成图反而让这道题目更加具象,而思考问题越具象,思路就越流畅,这就是为什么举例子是一个很好的说明方式。
言归正传。从小规模的图入手,因为大规模的图处理起来较复杂。
对于 ,很显然,图是一个正方形。不妨认为左上角是 ,左下角是 ,右下角是 ,右上角是 。
对于 ,事情变得有趣起来了。 分别构成了 的正方形,但 和 , 和 , 和 , 和 之间也有连边。将 代表的正方形放在左上角, 放在左下角, 放在右下角, 放在右上角,那么整个结构形如四个角都被标上直角符号的正方形。
对于 ,有了先前的思考,我们猜测图张成这样:将 的四张图按照上文提到过的顺序排列,然后在 和 , 和 , 和 , 和 之间连边,形成分形结构。

这张图也很好理解:如果想要改变 ,那么 必须相同。
到这里思路就很清晰了。
我们建出所有字符串的字典树,深度为 的结点(根节点深度为 )对应大小为 的分型结构。一个分形结构在比它大一级的结构中,只有四个端点是有用的。因此,设 表示在字典树结点 对应的分形结构中,从全是 的字符串走到全是 的字符串的 经过结构内所有关键点 的最短路,即任意两个端点之间的合法最短路。设 表示最长路。
根据实际意义转移即可,要求没有被经过的子结构内没有关键点。
例如,设 分别表示对应儿子,则:
- 令 。
- 如果 和 内没有关键点,则还可以用 更新 。
再记 和 表示经过结构内所有关键点的环。如果恰好一个结构内有关键点,则 可以直接继承对应结构的 。还可以用 更新 , 同理。
实现时,可以将 绑定在一起减少讨论。
注意当 时最小环为 。当 ,集合内两个字符串相邻时最小环也为 。为此,用 set
维护 。
时间复杂度 ,做到 是平凡但不必要的。代码。
A. Matching
若 则无解。
否则对于每个问号,若其位置为 ,则产生 的贡献,否则产生 的贡献。
代码。
B. Sort the Subarray
找到包含 的位置的 的极长不降子段即为答案。
代码。
C. Tear It Apart
直接枚举最后剩下来哪个字符,考虑不包含该字符的最长子串长度 ,若 则代价为 ,否则代价为 。
所有字符代价取 即可。
时间复杂度 。代码。
*D. Black Cells
将贡献拆成两部分:最后停下来的位置,加上两倍覆盖的区间数量。
只有 的段可能跳过,因为跳过 的段,虽然减少了一次 Shift 和 Release,但是至少增加了两次 Move,一定不优。
考虑枚举最后一段 ,设 长度为 的区间数量为 ,长度大于 的区间总长为 ,区间数量为 。
当 时,不用任何长度为 的区间,最后停在位置 ,区间数量为 ,且容易证明再往后枚举 一定不优。
否则,当 时,一定是 占满到 (否则就落在上一个情况了),最后停在位置 ,区间数量为 。
时间复杂度 。代码。
E. Rearrange Brackets
一个括号序列的代价是建树后所有点的深度之和。
把一个左括号挪到对应右括号左边,代价减小距离除以 。用栈求出每对括号之间的距离,排序后选前 大即可。
时间复杂度 或 。代码。
*F. Timber
好题。
从左往右枚举,一棵树能往左倒就往左倒。
设 表示第 棵树倒下的右边界为 ,那么对于 ,,因为左端点和右端点都可以倒。对于 ,。
问题转化为:选择 个数 且 ,求所有方案的 之和。
将 减去 ,转化为 和 。
注意到容易钦定 ,所以钦定 个 ,插板法得方案数为 ,则 ,其中 表示恰好 个 的方案数。
二项式反演得 ,则答案为
时间复杂度 。代码。
G2. Magic Triples (Hard Version)
设 表示 的出现次数。
对于 ,答案为 。
对于 ,枚举 ,考虑其所有非 因数 ,将 加入答案。
时间复杂度 :对于 , 的 不超过 ;对于 ,因数个数不超过 。直接根据 可得同样复杂度,但跑不满,可以通过。代码。
直接枚举 ,那么 的数量等于 的平方因子数量,即 。时间复杂度 。
可以通过哈希表将 因子去掉。
A. A-characteristic
枚举 的数量 ,则权值为 。
检查是否存在 使得权值为 即可。
时间复杂度 。代码。
B. Sort with Step
将下标和 均减去 ,因为排序过程不改变下标模 相同的位置的元素集合,所以答案为 当且仅当 。
若存在两个不符合的元素,交换它们可符合条件,答案为 。
否则答案为 。
时间复杂度 。代码。
C. Strongly Composite
对于三个不同的质数, 和 都是合法的。设质数 在 的幂次为 ,那么先贪心地不断将 加入 ,最后剩下若干 为奇数的质数 ,不断任选三个相乘加入 即可。答案即 。
容易证明这是正确的。
时间复杂度 。代码。
D. Unique Palindromes
考虑一个回文串第一次产生贡献的位置,那么这些位置互不相同。
对于相邻两个限制 ,若 显然无解。否则选连续 个位置填入第 个小写字母。
对于其它不产生贡献的位置,填入 abc
循环,那么只有开头的三个位置会产生贡献。注意到 ,故可行。
时间复杂度 。代码。
E. Removing Graph
度数为 的图由若干个环组成。
设 表示长度为 的链的 SG 值, 表示长度为 的环的 SG 值,打表发现当 或 时,SG 值为 ,当 时,SG 值为 。
实际上可以直接分析:因为 ,所以对于 且 ,总存在方案使得删去链后两侧长度相等,所以 。由此容易证明对于 有 。
时间复杂度 。代码。
F. Random Walk
以 为根,找包含 的子树,其它部分删去。
每次进入一个点,我们可以认为对该点的子树进行深搜,然后返回其父亲。那么点 的答案为其度数乘以 和 的公共长度。
特判 的答案为 。
时间复杂度 。代码。
A. LuoTianyi and the Show
将大于 的数去重。
设 和大于 的数量分别为 。
若第一次选择了 ,那么接下来只能选择 或大于 ,贡献为 。
同理,若第一次选择了 ,则贡献为 。
否则枚举第一次选择哪个大于 的数 ,设它在所有大于 的数中的排名为 ,则左边贡献为 ,右边贡献为 。
时间复杂度 或 。代码。
B2. LuoTianyi and the Floating Islands (Hard Version)
为奇数时重心唯一,答案为 。
为偶数时,若重心唯一,则产生 的贡献;若重心不唯一,则产生两重心之间最短路径长度的贡献。对于后者,枚举每条边,它产生贡献当且仅当两侧分别选择 个点,方案数容易计算。最后给期望加上 即可。
预处理阶乘和阶乘逆元,时间复杂度 。代码。
C. LuoTianyi and XOR-Tree
设 表示 到叶子所有路径异或和为 的最小代价,则先令 ,然后将 的所有 同时异或 ,最后将 和 取最小值。
这说明 的极差不超过 。维护 表示 , 表示取到 的 的集合,则:
- 第一步操作相当于合并所有 到 可重集 。
- 第二步直接打懒标记,设 表示 所有数要异或 才是真实值。
- 第三步设 最大出现次数为 ,若 ,则 ,否则 为 内取到最大 的所有数。对于后者,每个数出现次数至少减半,所以暴力遍历即可。
- 此外, 即 , 变成 。
- 对于叶子,令 ,。
启发式合并维护 ,时间复杂度 。代码。
D. LuoTianyi and the Function
从右往左扫描线,对于 和它下一次出现的位置 ,有
线段树维护区间赋值区间历史和即可。
时间复杂度 。代码。
*E. LuoTianyi and Cartridge
不好处理,枚举之,设为 。称一个点或一条边合法当且仅当 或 不小于 。
先考虑对某个 求答案。显然,若一条边一侧没有被选中的点,则该边一定不会被选中。反之,若每条被选中的边两侧均有被选中的点,则一定合法:按任意顺序加入选中的边,其两侧必然存在被选择的 不连通,否则 已经形成一个连通块,矛盾。
将不合法的边两端合并起来,得到一棵树 ,树上每条边代表一条合法边,每个点代表若干个点(可以全都是非法点),且叶子对应至少一个合法点:若叶子不对应任何合法点,则将其和与其相连的唯一的边删去不影响答案,因为该边不可能被选中。
此外,一个叶子至少有一个点被选中,否则与其相连的唯一的边无法被选中,往 加入该边和叶子内任意合法点,方案仍合法且权值增大。
因此,对于固定的 ,可以算出 的边数 ,其中 是删去了不合法的元素的点集和边集。
- 选点:选择所有叶子的权值最大的合法点,以及其它所有合法点的权值前 “ 减去叶子数量” 大的点。
- 选边:选择权值前 大的合法边。
考虑实时维护 :
- 对每个点 ,记录 表示对应所有合法点的权值。
- 对每个点 ,记录 表示它在树上的所有邻边。
- 维护所有叶子权值最大的合法点的点权之和 。
- 维护所有合法边权值构成的权值线段树 。
- 维护所有合法点去掉每个叶子权值最大的合法点的点权构成权值线段树 。
- 一个点是叶子当且仅当 。
考虑 在增大的过程中,会删去一些边或一些点。
对于删边,直接合并两侧的点,注意 和 需要启发式合并。
对于删点,若删去后得到了空叶子,则删除该叶子和与其相连的唯一的边。注意这个过程可能引发连锁反应(一个空心非叶子是合法的,所以删边可能导致某个空心非叶子变成空心叶子),用队列维护。
注意特判 的情况。
时间复杂度 或 (线段树合并维护 , 可以额外维护度数并懒惰删除将 set
换成 vector
)。代码。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!