构造/交互/Ad-hoc专题
P6663 [POI 2019] Układ scalony
首先,构造上下界。上界显然是 \(nm-1\),下界需要分奇偶讨论。右下左上联通,所以需要至少 \(n-1+m-1\) 的长度,我们发现对于 \(m,n\) 中有一个奇数的情况是可以满足的。在奇数那里从中间一列劈开,然后分别向两边连。对于偶数,我们无法到最中间的那个,那么只能选择相对更靠中间的那个。但是如果我们这么选
会造成长度加一,也就是 \(n+m-1\)。
最后的构造很显然就是调整法了。我们逐步将最小情况往大去调整,直到遇到答案。以 \(n\) 为奇数为例,我们先构造出红笔的主链,然后目前潜在的连边方式是黑笔的下界,如果我们要调整就一点一点地调整成蓝笔的上界,按照那个螺旋线一点点走就行。
我们可以设置一个标号数组,\(f_{i,j}\) 表示该点连边的朝向,初始化就初始黑边朝向即可。然后如果要变更,就改成蓝笔朝向。
本题在 \(n,m\) 为偶数的时候的构造,初始状态不要设置为图 \(1\) 中那种最小值情况,而是同理设置为图 \(2\),方便后续调整构造,图 \(1\) 形态不方便调整。
P9837 汪了个汪
由于题目要求二元组不同,于是思考二元组特征。
发现一共要填 \(\dfrac{n(n+1)}{2}\) 个二元组,而二元组的个数恰好也是 \(\dfrac{n(n+1)}{2}\),于是就是要根据二元组特征给全体二元组分类。且最好每一类的个数分别是 \(1,2...n\) 这样子正好对应每一行。可以根据二元组两个数之差来分类,这样子正好满足上述条件。
但是我们无法这么去安排数字,下面是一个小技巧,如果可以(相同数字代表一类)
这么放,那么我们同样可以
于是我们可以按照 \(x~x+1~x-1~x+2~x-2...\) 这么来放。最后根据长度排序即可。
CF1325C Ehab and Path-etic MEXs
首先特殊情况---链。 随便填。
其他情况的几种思考方式
-
可以自己试几组或者打表,发现答案均为 \(2\) ,于是往 \(2\) 上面构造。
-
根据 \(mex\) 性质考虑分离几个最小值,因为一条链上的一个点对这条链最多有两条边的贡献,所以取前三小值 \(0 1 2\) 放在一个点的三条出边上。
我自己的想法是考虑到要求的是 \(mex\) 的最大值以及 \(mex\) 的性质,于是可以想到一条叶子到叶子的路径比其他路径更可能对答案产生贡献。(好像对本题没啥用)
P7915 [CSP-S 2021] 回文
这题的构造策略是先选取序列的第一个(最后一个同理)加入 \(b\) 中,发现与 \(a_1\) 相同的那个 \(a_x\) 必须最后放入序列中。于是可以在 \(a\) 数组中以 \(a_x\) 为分界点,此时切记不可再考虑选取 \(a_2\) 或者 \(a_{2n}\) 再次选取分界点。而是应该根据 \(a_x\) 为最后一个推导出 \(a_{x-1}\)或者 \(a_{x+1}\) 为潜在的倒数第二个,于是在序列两端寻找能否找到与 \(a_{x-1}\) 或者 \(a_{x+1}\) 相同的数作为 \(b_2\) 。以此类推,即可完成构造。
AT_arc144_c [ARC144C] K Derangement
构造可行解,在条件允许范围内微调使得更优。判断一下如果该数往前放的话,目前的位置可以有其他数字填补就可以进行操作。
CF1311E Construct the Binary Tree
很显然的就是先构造出一组极限情况,然后不断调整。这里以先构造一棵满二叉树为例。构造出以后,感觉自己思路还是有点乱,想的有点放开了,以为是一堆点移来移去,这样子显然是很完成构造题的。还是要大胆猜想出一个一般性策略然后实现。由于极限情况是一条链,所以我们可以把目标设置为链形。首先维护一条链,然后不断把树上节点挂上去。如果 \(rest_d\) 突然小于 \(0\),说明目前链长大于 \(-rest_d-dep_i\),故一定可以在链上找到一点使得 \(rest_d =0\) 并且该点没有挂上子节点,往上放就可以了。
CF1916F Group Division
考虑动态构造这个集合,每次选取剩余图上的与选取图联通的非割点加入即可。
如果要严谨点,可以证明一下存在性。
CF1736D Equal Binary Subsequences
首先 \(0~1\) 个数不相等肯定不行,我们可以大胆猜测一下个数相等的时候必然可以。其实我们也可以发现满足情况的可能很多,所以可能并不能直接找到一个通法。但这也说明了操作空间很大,我们可以钦定一种方案,强行构造。肯定选择相对便利的方案尝试构造,如果两组中对应位置在 \(s\) 中差距过大,那么难以操作,于是我们可以采取一些方法使得两组中对应位置相邻。效果就是类似 \(0011001111110000\) 。考虑分组,\((i,i+1)\),当 \(s_i=s_{i+1}\) 显然可以,我们将不相等的位置提取出来,必定形如 \((1,0)~(0,1)\) 交替着选出 \(0~1\) 然后平移即可。
CF1521E Nastia and a Beautiful Matrix
构造最小矩阵,一般要考虑答案下界,我们发现在 \((2x,2y)\) 的位置填入 \(0\) 剩下的位置填入 \(0\) 这样子显然是最大化的。此时可以填入 \(n^2-\lfloor \frac{n}{2}\rfloor^2\) 个数。设出现次数最多的数出现了 \(Max\) 次。那么为了实现要求 \(2\),需要满足 \(n\lfloor \frac{n}{2}\rfloor \ge Max\),于是二分出最小的边长同时满足两个条件即可。这只是必要条件,为了使得结论充要,下面我们需要给出一个满足条件的构造。条件一是已经满足的了,条件二需要我们让相同数字尽可能在同一行或者隔 \(2\) 行及以上,而非相邻行。直接对于 \(a_i\) 排序,把 \(a_i\) 个 \(i\) 依次放到一个序列中。按照序列顺序放到所有 \((2x+1,y)\) 上,放完之后再放 \((2x+1,2y+1)\) 这显然是更可能的去贴合条件二的情况。下证这构造满足条件二,发现对角线的两个数在序列中位置相差 \(\ge n\lfloor \frac{n}{2}\rfloor\),由上述二分可知,没有某个数出现次数大于 \(\ge n\lfloor \frac{n}{2}\rfloor\) 因此得证。
CF1365G Secure Password
首先可以转化一下题意:每次可以询问一个集合,要求最后对于每一个 \(i\) 需满足询问的集合中不含 \(i\) 的集合的并集等于全集去掉 \(i\)。
其实就是一个集合划分问题,再进一步转化一个上面的条件也就是对任意 \((i,j)\) 满足 \(j\) 出现在一个不含 \(i\) 的集合中。于是我们可以通过元素特征来划分集合。\(i\) 和 \(j\) 不同当且仅当二者的二进制表示中有一位不同,这启发我们考虑二进制的每一位分别询问下标的当前位为 \(0\) 和 \(1\) 的元素的集合。但是这样操作次数是 \(20\) 次。
如何减少操作次数呢,发现操作次数是等于集合总数的,于是我们可以通过减少集合总数来削减操作次数。在当前的划分方式下 \(20\) 个集合确实是必要的,因为只有这样才能区分出那些只有一位不同的数,所以我们可以选择更具有特征性的划分方式。
我们发如果固定 \(1\) 的个数这样不需要对于每一位正反查了,因为如果当前位 \(i\) 为 \(0\) 而 \(j\) 为 \(1\),那么必然存在另一位使得 \(i\) 为 \(1\) 而 \(j\) 为 \(0\),只需要在 \(1\) 的位置统计就可以了,这样就不需要正反询问了。
为什么询问次数上限是 \(13\) 呢,因为 \(C_{12}^i \le C_{12}^6 <1000\),而 \(13\) 恰好满足条件。
P9721 [EC Final 2022] Inversion
区间逆序对显然是不好得出什么结论的,于是我们考虑将区间逆序对转化为有用的东西。
这里一定要敢想,交互题一开始的思路就是先能做出来,再考虑次数限制。所以我们不要吝啬操作次数。我们发现可以用 \(4\) 次询问容斥原理得出 \(a_l\) 与 \(a_r\) 的相对大小关系。
得到的关系只是相对关系,这启发我们动态地维护相对大小,最后就可以得到总的序列。
设 \(pos_i\) 为目前相对排名为 \(i\) 的数的位置,\(a_i\) 表示 \(i\) 位置目前的相对排名。
每次新加入一个 \(p_i\),我们要求出 \(a_i\) 也就是 \(p_i\) 的相对排名。可以二分一下排名就行了,用所给函数来比大小。最后还需要来考虑一下次数。
第一个优化是记忆化。第二个优化发现对于 \(i\) 的每个询问要用到两次 \(f(k,i-1)\),我们很可能要调用函数计算,但其实不用,因为我们已经得出了前 \(i-1\) 个数的相对大小,所以可以直接判断。故其实一次询问只需要调用两次函数。
P3641 [APIO2016] 最大差分
\(T=1\), 的时候我们直接询问 \((0,10^{18})\) 便可以得出最大最小数,然后把最大最小数往中间缩一就可以得到次大和次小,以此类推得到整个数列。
\(T=2\),次数约束的是区间内数的个数,我们发现区间内数的个数越多,答案应该是越小的,而我们要求的是最大化答案,所以两者之中存在一个平衡。这里我们取 \(B\) 为答案下界,\(B=\frac{a_n-a_1}{n-1}\),每次跳跃着查询即可。答案只会是上一个块的最大值和当前块的最小值之差。考虑 \(M\) 是否符合要求,第一次 \(M \gets n+1\),后面会询问 \(n-1\) 次,总共覆盖到 \(n-2\) 个数,于是 \(M \gets n-1+n-2\),所以总数是 \(3n-2\)。
CF1158C Permutation recovery
一眼线段树建图+拓扑排序。不过还有更简便的方法。不过仔细考虑一下就是需要满足 \(i \to p_i\) 不相交就行了,于是单调栈判断一下就行了。考虑 \(-1\) 如何处理,我们发现 \(i\) 和 \(p_i\) 越近越容易满足条件于是直接设为 \(i+1\) 即可。然后需要构造,我们肯定是先构造出约束条件最少的,所以直接按照 \(p_i\) 降序,\(i\) 升序把 \(n-1\) 填入即可。
CF1354G Find a Gift
基本想法肯定是找出一些石子做参考物,然后比较。
问题是我们很难找到很多石子,但是发现石子的个数大于一半,且重量唯一最大,于是随机 \(\log n\) 个位置取重量最大的就大概率是石子了。现在我们得到了一个石子,显然是不够支持我们做大规模询问的,我们单组询问的规模是和已知石子的个数相等的,这里可以倍增,如果目前询问的一组里面没礼物,那么就必然全是石子且可以供我们所用。
CF1493F Enchanted Matrix
发现行列独立,可以分开处理。只需要在 \(n\) 或者 \(m\) 的约数中寻找。对于任意 \(r\),如何判断合法性呢,根据 border 结论,只需要比较 \((1,n-r)\) 与 \((r+1,n)\) 即可。但是本题要求不重叠,我们不能这么问。拆分一下即可,\((1,mid)~(mid+1,2*mid)\) \((1,mid)~(mid+r+1,2*mid+r)\)
CF1514E Baby Ehab's Hyper Apartment
先确定思路,我们判断大部分联通应该都是用到了联通传递性。于是根据竞赛图的性质我们先找出一条哈密顿路,然后顺着走显然就可以了。现在要逆着往回走,我们发现哈密顿路上越靠前的点可以走到更多的点,因为后继点能到达的地方他们也必然可以到达。这里就出现了单调性,可以通过多点查询双指针查一下。如何找到哈密顿路呢,这里可以采用合并法也就是合并 \((l,mid)\) 和 \((mid+1,r)\)。先找到两段的起点,看哪个起点可以指向另一个起点就将其作为总的起点,以此归并,可以直接 stable_sort 一下,比较函数就是点点查询。注意一下点集查询只能查是否有边,不能查所有边,所以可以考虑反过来通过没有边得出点集内所有都不可达。
CF650E Clockwork Bomb
初始树为 \(T1\),目标树为 \(T2\)。
考虑一下下界显然就是在 \(T1\) 在 \(T2\) 中没有出现的边的数量。
但是我们需要满足每次操作完仍然是一颗树。我们发现某个节点只要向上连边就必然保持树的形态,如果向下连边就会出现环。于是我们从叶子节点开始向上遍历即可。
注意处理特殊情况,\(T1\) 和 \(T2\) 中父子颠倒。如果在 \(T1\) 中 \(u\) 为 \(v\) 父亲,可是在 \(T2\) 中 \(v\) 为 \(u\) 父亲,那么我们要保留边 \((u,v)\),可以在从下往上遍历到 \(v\) 的时候,如果 \(v\) 要连自己在 \(T2\) 中的父亲的话,就要断开 \(T1\) 中的边 \((u,v)\) 否则可能成环。矛盾。
于是我们将断开 \(T1\) 中的 \((u,v)\),改为断开 \(T1\) 中 \((fa_u,u)\),这样既保留了边 \((u,v)\),又保证不会成环。可是同理如果 \(T1\) 中的 \((fa_u,u)\) 在 \(T2\) 中也出现过怎么办呢,我们可以采用并查集,找到该链上第一个不同时出现的边断掉即可。
P3514 [POI2011] LIZ-Lollipop
看到这题我的第一反应是每次 \(+-1\) 造成值域连续性,本题中如果是 \(0 1\) 序列的话值域也是连续的。可是这里有一个 \(+2\),按照前面的思路来想,可以发现这里是 \(2-\) 连续的。
假设 \([l,r]\) 和为 \(x\),如果两个端点是 \(1\),我们可以同时拖动两个端点使得其变成 \(x-2\),如果两个端点中出现一个 \(2\),我们也可以减去它构造出 \(x-2\)。
CF468C Hack it!
我们发现单独的各位数字累加没有什么规律或者好用的性质。
于是可以思考两两配对。就是令 \(p=\sum\limits_{i=1}^{10^{18}}i \bmod a\),然后把上界 \(+1\),下届 \(+1\),就可以发现增量就是 \(1+18 \times 0=1\),一直增加直到满足要求即可。
P7115 [NOIP2020] 移球游戏
先思考 \(n=2\) 时候的解法,记录两个栈为 \(s_1\) 和 \(s_2\),分别目标为 \(1\) 球和 \(2\) 球。我们现在想要其中一个栈变成全 \(1\)。我们发现 \(s_1\) 和 \(s_2\) 都往空栈里面放一点东西进去似乎只有暴搜放进去的顺序然后 \(2\) 和 \(3\) 栈互相搞一下的很暴力的做法,没有可扩展性。有没有什么好办法去分离 \(1\) 和 \(2\) 两种小球呢,只有两个空栈能办到。我们现在只有一个空栈,转念一想,其实我们可以再创造半个空栈,设 \(s1\) 中有 \(a\) 个 \(1\),那么我们只需要从 \(s_2\) 中挪 \(\min(a,m-a)\) 个球给 \(s_2\),然后将 \(s_1\) 中球依次弹出,分别放到 \(2\) 和 \(3\) 中这就实现了分离。
那么对于 \(n>2\) 的时候呢?把问题转化到 \(n=2\)!直接设置一个阀值 \(x\),然后 \(\operatorname{solve}(l,r)\),把 \((l,r)\) 分成两半,两边两两匹配,然后大的到一边小的到一边就行了。
还有一种解法是按照 \(n=2\) 的相同手法对于双栈进行排序,使得 \(\max s_1 \le \min s_2\),然后对于所有栈归并排序一下就行了。
P9731 [CEOI2023] Balance
先考虑 \(S=2\) 的做法,我们对于
对于 \(S\) 更大的做法,我们先做 \(S=2\) 然后分治下去。