Ad-hoc 题目总结
明天补双序列。
这是一年前写的:https://www.becoder.com.cn/article/14590。
现在我在其基础上,再补充这一年做的一些新题。
力推:https://www.cnblogs.com/rainybunny/p/15398779.html。
我先逗大家乐一下:
Ad-hoc 题可能不一定能找出实力最强的选手,但一定能找出最适合做出题人 npy 的选手。
属于“思维体操”,做之前会异常兴奋,做之后会只想睡觉。
1 总结
Ad-hoc 是对一类特殊题目的统称,包含构造。这类题目往往没有套路的方法。考察选手的观察力和思维力。
1.1 利用特殊性质
在这类题目中,挖掘特殊性质是关键。有时候出题人会给你特殊性质,那么请不要犹豫。因为出题人通过特殊性质,已经把解题的道路给你铺开了。绝大多数题目都是这样组成:
-
首先你要会特殊性质的做法。然后你需要想办法再进行操作,使得题目的约束简化成特殊性质的约束。2.1 2.5。
-
你要会 A 和 B 性质分别怎么做。如果你知道把 AB 结合起来该怎么做,正解就出来了。2.2。
1.2 快速找到性质
虽然这类题很容易被天赋哥拉开差距,但我们仍可以总结一些常用的技巧来快速地“注意到”某些关键性质和突破口。
-
操作在何时一定成立 / 不成立。或者哪些东西是恒变的 / 恒不变的。
- 2.1 中,当 \(a_i/a_j=1\),或 \(a_i=a_j\) 时一定有贡献。
- 2.2 中,长度为 2 的不相同字符一定不回文。
- 2.4 中,\(n\) 一定会作为一个字串地最大值。
- 2.6 中,不同颜色地两点间有环时一定满足。
- 2.10 中,当 \(p_i=1\) 时一定交换 \(p_j,p_k\),\(p_i=n\) 类似。
- 2.11 中,数 \(n\) 在 Task1 中不会带来变化;Task2 中会让所有后面的所有前缀积积变成 0。
- 2.12 中,\(p_i \bmod 3 = 0\) 的数一定不影响。
-
题目给的范围 / 上限为什么这么奇怪?
- 2.1 中,\(a_i\) 上界是 \(2n-1\),用来构造什么的?
- 2.3 中,\(x\) 上限比 \(m\) 大,是不是要询问很大的 \(x\)?
- 2.10 中,为什么 \(L\) 可以取到 \(O(n)\) 级别?
- 2.5 这个上界比较奇怪。但也可以提醒我们将 \(b,c,d\) 构造地不要太大,控制在和 \(a\) 一个数量级。
-
首先尝试直觉 / 最简单的构造 / 方法。能否通过调整使之满足限制 / 有解?
- 2.7 中,肯定构造菊花图,具体怎么生成?
- 2.11 中,Task2 能否就让前缀积顺序取 \(1,2,...,n\)?
- 2.12 中,可以把 \(p_i\) 相同的放在同一层。让 \(p_i=1\) 放在奇数层,\(p_i=2\) 放在偶数层。如何结合?
-
考虑枚举第一步。接下来的问题是否更简单了?
- 2.9 中。
- 2.14 中,枚举第一步是左还是右就划分成了两个栈的问题。
2 例题
2.1 P11277 世界沉睡童话
构造一个长为 \(n\) 正整数序列 \(a\),满足恰有 \(k\) 组无序正整数对 \((i,j)\),满足 \(\max(a_i,a_j)\) 是 \(\min(a_i,a_j)\) 的倍数。你需要保证 \(a_i\le 2n-1\)。
部分分:\(k=0\);\(k\le n-1\)。
先考虑 \(k=0\) 怎么做,显然就是要构造所有数都互质。直接从 \(n-1\) 到 \(2n-1\) 即可。
\(k\le n-1\):这是比较难的部分。
我首先想到:构造一系列类似 \(x,2x,3x,...,px\) 的东西,每个代价是 \(\frac{p(p-1)}{2}\)。每次二分最大的 \(p\),让 \(k\) 不断逼近 0 即可。
但是这样细节比较多而且没有很快的找 \(x\) 的方法。并且还有一个最大的问题:可能构造的 2 组互相满足了倍数关系!直接完蛋!
让 \(k\) 不断逼近的思想是好用的。要优化我们的构造。
注意到题目没有让所有数不同。很快地想到等效构造:\(p\) 个 \(x\)!
如何使得这些 \(x\) 互质?使用 \(k=0\) 时构造的那些数即可。
到这里就解决了 \(k\le n-1\) 的问题,对于 \(k\ge n\) 的部分,我们自然尝试将 \(k\) 变小直到 \(k\le n-1\):
一个观察:如果一个数对中有 \(1\),那么其一定有贡献。
每向序列中加入一个数 \(1\)(假设现在一共有 \(i\) 个),就会带来 \(n-i\) 的贡献。
一直加入 \(1\) 直到 \(k\le n-1\),此题解决。
此题的思考方向:\(k=0\) 和 \(k\le n-1\) 的构造 -> 构造操作使得 \(k\le n-1\)。
2.2 P11190 「KDOI-10」反回文串
给定一个长度为 \(n\) 的字符串 \(s\),你需要把 \(s\) 分成若干个非空子序列,使得每一个子序列都不是回文的,并最大化划分成的子序列数。
特殊性质 A:保证 \(n\) 是偶数,且 \(s\) 中每个字符的出现次数都不超过 \(\frac{n}{2}\);
特殊性质 B:保证 \(s\) 中仅有a
和b
。
突破口:长度为 2 的不相同字符一定不回文。
特殊性质 A:直接构造所有子序列长度为 2。问题变成找到 \(n\) 对互不相同的数。将字符串排序。并将 \(i\) 和 \(i+\frac{n}{2}\) 配对。如果 \(2\nmid n\),则把中间那个数加入 \((1,n)\) 即可。注意不能随便加!否则可能出现 aba
类似的回文。
其他情况下会有一个绝对众数 \(a\),肯定每个子序列不能只是由 \(a\) 组成了。但是可以类似地构造:先放一堆长度为 2 的,最后再把剩下构造一组,这一组有 1 个不是 \(a\) 的,其他全是 \(a\)。
如何避免剩下这个字符串是回文的情况?想到:把不是 \(a\) 的最前面的和 \(a\) 最后面几个匹配。发现 wa 了。于是再判断把不是 \(a\) 最后面的和 \(a\) 最前面几个匹配。过了。证明简单。
此题的思考方向:A,B -> 正解
2.3 P11145 「SFMOI Round I」Strange Homura Game
\(m\in [2,10^{17}]\) 未知,你需要询问不超过 2 次来确定 \(m\)。每次询问给出 \(x\in [0,10^{18}]\),返回 \(x\bmod m\) 的值。
一个性质:当 \(x<m,x\bmod m=x\)。
所以可以二分 \(x\) 来询问,找到最大的 \(x\bmod m=x\),\(m\) 既是 \(x+1\)。该方案询问次数:\(\log V\)。
注意到 \(x\) 上限比 \(m\) 大。直觉告诉我们询问的 \(x\) 必须非常大。(尝试构造小的 \(x\) 无果)
又一个性质:\(m\mid (x-x\bmod m)\)。这里的限制就非常强了!我们只需要让两次询问的 \((x-x\bmod m)\) 的公因数唯一,就解决了!
事实上,这样的 \(x\) 是不好找的。放弃这个方法。
不妨先询问一次得到:\(m\mid (x-x\bmod m)\)。把后面那个东西减一,有:
所以第二次询问必定会返回 \(m-1\),此题结束。
此题的思考方向:先询问使得 \(m\) 是一个数 \(k\) 的约数 -> 发现 \(k-1\) 返回的是 \(m-1\)。
2.4 P11132 【MX-X5-T4】「GFOI Round 1」epitaxy
构造一个 \(n\) 阶排列,使得排列中:“所有的 \(n - m + 1\) 个长度为 \(m\) 的连续子串内最大值的最大公因数”最大。
突破口:最大值。
必然有一些子串的最大值是 \(n\)。所以我们就需要让其他子串的最大值都是 \(n\) 的约数。
先判掉把 \(n\) 放到中间就是所有子串的最大值的情况。
我们肯定希望这个 gcd 是 \(n\) 的不包含自身的最大因子 \(x\),并且不能比 \(m\) 更大。下面给出一种构造方案证明一定可以。
首先我们需要所有子串的最大值都是形如 \(kx\le n\) 的形式,贪心地让他们相隔尽量远,都放在 \((k-1)m+1\) 的位置。
然后我们只需要把剩下的数放进去,并且使得他不是任何一个子串的最大值即可。从小到大放就可以了。
为什么这样一定可行,首先由于 \(x\mid n\),所以每一段的大小都是相等的,每一段的第一个位置都是 \(kx\),这一段后面跟的数都小于它,所以最大值也没有被替代。
举例:
当 \(n=12,m=3\),构造如下:
\(*3,1,2,*6,4,5,*9,7,8,*12,10,11\)
注意标星号的位置,看看他们是不是完全包含了所有子串的最大值。
此题的思考方向:最大值 -> 枚举 \(n\) 的每个约数判断是否合法 -> 发现 \(n\) 的最大不超过 \(m\) 的约数一定可以构造。
2.5 P11036 【MX-X3-T3】「RiOI-4」GCD 与 LCM 问题
给定正整数 \(a\le 10^9\),构造三个正整数 \(b,c,d\) 使得 \(a+b+c+d=\gcd(a,b)+\operatorname{lcm}(c,d)\)。你需要保证 \(b,c,d\le 1\,634\,826\,193\)。
部分分:\(2\nmid a\)。
首先尝试:\(b=1\),那么要求:\(a+c+d=\operatorname{lcm}(c,d)\)。
自然地想到让 \(c,d\) 与 \(a\) 有关,最好右边是个 \(2a+k\) 的形式。那么构造:\(c=2,d=a+2\)。这组构造当 \(2\nmid a\) 时成立。
自然考虑 \(2\mid a\) 的情况。其它做法留给打表哥。
类似 P11277 的思想:能不能回到 \(2\nmid a\) 的情况?比如,我把 \(a\) 拆成:\(2^w\times k\),满足 \(k\) 是奇数。显然一定可以拆成这样的形式。
把 \(c,d\) 都调整:\(c=2^{w+1},d=2^w\times k+2^{w+1}\)。带入原始式子:
不难证明后面的 lcm 的结果是:\(2d\)。把 \(a,c,d\) 带进去:
\(a+c+d=2d\)
显然 \(a+c=d\),于是得证。
此题的思考方向:数学直觉 先确定难搞的 gcd,考虑 lcm -> 发现构造只满足 \(2\nmid a\) -> 构造 \(2\mid a\) 的情况。
2.6 P11022 「LAOI-6」Yet Another Graph Coloration Problem
小 R 有一张 \(n\) 个节点和 \(m\) 条的边简单无向图,节点的编号依次为 \(1 \sim n\)。她想要为图中的每个节点分配黑色或白色的颜色,使得:
- 有至少 \(1\) 个黑色节点和 \(1\) 个白色节点;
- 对于任何一对点对 \((u, v)\),只要 \(u\) 和 \(v\) 的颜色不同,就存在至少 \(2\) 条从 \(u\) 到 \(v\) 的不同的简单路径。
突破口:至少 2 条路径。想到构造一个环(\(\ge 3\)),只要两点之间的路径要经过环,那么他们就一定有 2 条以上的路径。
我们发现如果这个图没有环一定无解。
一个环把整个图划分成了若干个不相关的子图,我们想到让每个子图颜色相同。这样内部就不用管了。
考虑结合起来,环上每个点的子图交替染色即可。
考虑一种特殊情况:环上一个点 \(x\) 的子图和环上另外一个点 \(y\) 相连。此时如何染色?
让这个子图和 \(y\) 断开,即使得 \(x\) 和 \(y\) 的子图染不同颜色,并钦定这个子图不属于 \(y\) 的子图。
容易证明这样构造合法。上述情况本质上是环上接了另外一个环。
此题的思考方向:参照环 -> 环外所有子图内部染相同颜色 -> 结合起来交替染色。
2.7 P10678 『STA - R6』月
给定正整数 \(n\) 和每个点 \(i\) 的度数 \(d_i\),你需要构造一棵树,最小化其直径。
很容易想到菊花图的构造方式。麻烦的是对于每个点的度数的限制。
猜想:按照度数从大到小,依次接入点。
证明即构造:希望尽可能地使层数浅的点更大。
模拟是简单的。
此题的思考方向:菊花图 -> 贪心/证明
类似题:CF1092E
给定一张图,由若干森林组成。请给这张图再添加若干条边,使得这张图变成一棵树,且树的直径最小。
解:求出每个树的直径中点,并都接到其中一个中点上去。枚举接哪个中点即可。
2.8 P9915 「RiOI-03」3-2
给定一个正整数 \(n\)。将 \([0,2^n)\) 中每个整数的二进制最低 \(n\) 位从低到高依次写在一个 \(2^n\times n\) 的矩阵上。矩阵两维的下标都从 \(0\) 开始。 给定 \(q\) 次询问,每次询问这个矩阵下标为 \((x,y)\) 的格子所在的四连通块大小对 \(998244353\) 取模的值。下图是 \(n=3\) 的情况:
说实话没什么突破口,尝试打一个大一点的表。
性质:所有连通块的右边界都是整齐的一列。并且都存在一行使得最左边是第 0 列。
证明可以考虑从 \(x\to x+1\) 的进位情况。
打表还可以发现每个连通块不同列都是 \(2^j\) 的大小,于是总和就是 \(2^{\max j+1}-1\)。所以我们就只需要找到最右边那一列。
暴力人人都会:直接向右枚举 \(y'\),判断 \(x\) 行上 \(y\) 和 \(y'\) 列的数是否相同即可。是 \(O(n)\) 的,无法通过。
观察数据范围:\(x\le 10^{18}\)。也就是说当 \(y>\log x\) 时,这个连通块一定全是 0,并且顶到了 \(n\) 这一列。所以我们的 \(y\) 就变成了 log 级别。
此题的思考方向:打表发现性质 -> 找到询问点的右边界 -> 观察数据范围优化算法。
2.9 P9870 [NOIP2023] 双序列拓展
2.10 P9347 似曾相识燕归来
给定一个长度为 \(n\) 的排列 \(p\)。现在可以进行至多 \(L\) 次如下操作:
- 选定三个整数 \(i,j,k\) 满足 \(1\le i<j<k\le n\),如果 \(p_i>p_k\),交换 \(p_i,p_j\);否则交换 \(p_j,p_k\)。
构造方案使得 \(\forall 1\le i\le n\) 都有 \(p_i=i\)。满分限制:\(L=n\)。部分分:\(L=n+1/n+2\)。
提醒:此题需要分讨多种情况,请预留充足的时间。
避免被 corner case 卡,先特判 \(n\le 4\) 的情况。
发现操作没有规律,不妨先固定一位:先让 \(p_1=1\)。
接下来我们只需要操作至多 \(n-2\) 次就可以排序,依次枚举 \(i,pos_i\) 并操作 \((1,i,pos_i)\) 即可。
现在问题变成:如何通过 \(2\) 次操作使 \(p_1=1\)?
观察操作,我们希望让 \(j=pos_1\)。并且 \(i=1\)。那么 \(k\) 就需要是 \(pos_1\) 后面的小于 \(p_1\) 的数的位置。
如果存在 \(k\) 那么一次操作即可解决,否则还需要一次操作使得 \(k\) 存在。(特判 \(p_n=1\),此时一定无解)
如何操作使得 \(k\) 存在不难,不细说了。
\(p_1=2\) 的情况呢?注意到无法通过 2 次操作完成。所以这样构造:通过 3 次操作,使得 \(p_1=1,p_2=2\)。或者类比地进行多次操作。
后面的构造就比较繁琐和考验耐心了,也并不容易。这里就不展开了。笔者被恶心到了。
此题的思考方向:\(p_1=1\) 后 \(n-2\) 步 -> 构造 \(p_1=1\) -> 原始 \(p_1\ge 3\) 好做 -> 考虑 \(p_1=2\)。
2.11 P3599 Koishi Loves Construction
Task1:试判断能否构造并构造一个 \(n\) 阶排列,满足其 \(n\) 个前缀和在模 \(n\) 的意义下互不相同。
Task2:试判断能否构造并构造一个 \(n\) 阶排列,满足其 \(n\) 个前缀积在模 \(n\) 的意义下互不相同。
突破口:数 \(n\) 放的位置。
都先把 \(n=1\) 特判了。
Task 1:
\(n\) 对于我们的前缀和没有任何的影响。所以必须放到开头。
这说明一定有 \(0\) 的前缀和,注意到无论怎么排列这个排列一定有前缀和(所有数的和):\(1+2+...+n=n(n+1)/2\)。所以当 \(2\mid (n+1)\) 时这玩意模意义下为 \(0\),无解。
回到构造上,看看直接构造前缀和为 \([1, n]\)。失败。
考虑反复横跳。这是我编的,但这个构造方法真的很常用。发现构造 \(n,1,n-2,3,n-4,5...\) 满足约束。
感性理解可以把每一对 \((i,n-(i+1))\) 这种视作给前缀和 -1。
Task 2:
类似地,数 \(n\) 后面的前缀积全部是 \(0\)。所以它必须放在最后。
接下来的构造非常清新:逆元。
不妨先设 \(n\) 是质数。并且最简单地构造 \([1,n)\) 作为前缀积的排列。每次要满足:\((i-1)\times p_i\equiv i\pmod n\)。可以直接逆元算出 \(p_i\)。
很容易证明这样子构造的 \(p\) 是一个排列。
\(n\) 不是质数的情况?感觉好像都不合法啊,毕竟有因子了。而且逆元不唯一。
但事实是,当且仅当 \(n=4\) 的时候排列:\(1,3,2,4\) 合法。记得特判。
此题的思考方向:特殊值 \(n\) 的位置 -> 尝试最简单的构造方式/打表找通解 -> 证明其他情况无解(这一步可以省去)。
2.12 AT_hitachi2020_c ThREE
给定一棵树,要求构造一个排列 \(P\),使得:对树上的每一对点 \((i,j)\),如果这两个点之间的距离为 \(3\),则 \(p_i\times p_j\) 和 \(p_i+p_j\) 中至少一个为 \(3\) 的倍数。
看到距离为奇数尝试按深度奇偶来做。
若 \(p_i\bmod 3=0\) 则放到哪里都可以(不妨最后放),若 \(p_i\bmod 3=1/2\) 则要求和 \(2/1\) 或 \(0\) 匹配。所以问题就是怎么分配 \(1,2\)。
注意不一定非要把 1 放奇,2 放偶,因为他们之间的距离是奇数但不一定是 3。所以优先肯定考虑的是:让一个值(1/2)能在一个深度被分配完。满足这个的时候,才需要让他们奇偶不同。后面就在剩下的地方放 0 即可。
证明省略。
可以用 vector
维护深度奇偶的点集,每次取 back 并弹出即可。
此题的思考方向:发现 1 和 2 结合以及 3 的特殊性 -> 按照奇偶进行构造。
2.13 CF1990C Mad MAD Sum
很多题目都满足一个性质:操作若干次后恒不变。根据这个可以秒掉一堆 Ad-hoc 题。这个题虽然只有 *1500,但其每次操作都有一定的变化,只不过变化是有规律的。较前面那种纯模拟题要有趣一些。
打表发现:原数组操作常数次后形态变化稳定。
于是先暴力操作常数次,然后观察后面每次操作如何变化。
自己构造一组数量级在 10 左右的数据并打表,发现每次数的种类和相对位置不变,整体向右平移 1,超过 \(n\) 的位置永远消失。
然后就可以统计贡献了,这个不是本题的难点。
此题的思考方向:操作若干次后数组稳定 -> 观察每次操作的变化 -> 维护贡献。
2.14 P7915 [CSP-S 2021] 回文
给定正整数 \(n\) 和长为 \(2n\) 的序列 \(a\),在这 \(2 n\) 个数中,\(1, 2, \ldots, n\) 分别各出现恰好 \(2\) 次。现在进行 \(2 n\) 次操作,目标是创建一个长度同样为 \(2 n\) 的序列 \(b_1, b_2, \ldots, b_{2 n}\),初始时 \(b\) 为空序列,每次可以进行以下两种操作之一:
- 将序列 \(a\) 的开头元素加到 \(b\) 的末尾,并从 \(a\) 中移除。
- 将序列 \(a\) 的末尾元素加到 \(b\) 的末尾,并从 \(a\) 中移除。
我们的目的是让 \(b\) 成为一个回文数列。输出字典序最小的操作方案。
容易发现每次操作确定后,其对应的第 \(2n-i+1\) 次操作选的数也就对应了。但是这样过后就没有思路了。
不妨枚举第一步选左边还是右边的元素。并找到相同元素的位置 \(pos\) 作为断点。假设先选的是 1,那么原问题变成了:\([1,pos),(pos,n]\) 的两个问题。记为 \(c,d\)。
每次只能选 \(c\) 的左边或 \(d\) 的右边删。并且其对应的倒数次删的位置必须在 \(c/d\) 的底部(靠近 \(pos\))的那一侧,否则删到最后一定无解。
字典序最小是很好模拟的,只需要分讨 4 种情况。无解也不难判断。
此题的思考方向:一次操作确定了第倒数次操作 -> 枚举第一步操作什么 -> 划分成双栈问题,再模拟。