非传统题型选讲
本处的非传统题,指构造、交互、提答、通信等这一类较传统问题不同,解法不普遍的题型。
本文将会讲解一些这样的题,并给出一些题的通用方法。
配套题单。
知识点
先复习一下简单的知识点,然后进入我们的讲题。
鸽巢原理
将 \(n\) 个物品分为 \(k\) 份,最大的一份至少为 \(\lceil \frac{n}{k}\rceil\) 个,最少的一份至多有 \(\lfloor \frac{n}{k}\rfloor\) 个。
矩阵染色
对某一个 \(k\),将矩阵中的每个位置 \((x,y)\) 染上第 \(x+y\ \bmod\ k\),使得相连的 \(k\) 个格子颜色不同。
DFS 树
给定一个无向图或有向图,用 DFS 找出图中的一棵生成树。
重要的事实:无向图的非树边一定是后向边。
随机化
随机永远会是最后的手段,有的题目使用随机是有一定作用的。
分块
是的没错,分块永远是适配于所有题目的。
常见的方向还有二进制分解,二分,分治,递归,限于篇幅不再一一赘述。
这些都是解决这一类非传统题型的利器。
例题
2020 美团杯 最长公共子序列
这是一道水题。
显然如果我们选择询问 \((i,j)\),若 \(i\) 的位置在 \(j\) 之前,询问则会返回 \(2\),否则则会返回 \(1\)。
那么我们询问一组 \((i,j)\),就可以得到 \(i\) 与 \(j\) 的相对关系,做一遍快速排序即可。
IOI 2014 Game
要想在前 \(r-1\) 个问题中不让对手猜出答案,当且仅当最后他问的一条边如果在图中是桥边。
由于最后一个回答没有作用,所以我们假设最后一个问题的答案为真,即整张图为连通图。
然而对手问的边不一定,所以我们要最大化桥边数量,哪种图的桥边最多呢?树!
我们随便取一个点 \(n\),显然对手会问 \(n-1\) 次与 \(n\) 有关的信息,考虑在前 \(n-2\) 次回答假,在最后一次回答真。
那么,总的策略就是,对于询问 \((u,v)\),其中 \(u<v\),如果这是关于点 \(v\) 的第 \(v-1\) 次询问,回答真,否则回答假。
JOISC 2020 Legendary Dango Maker
提交答案题有大量的解法,包括但不限于找性质、贪心、爆搜等各种奇淫技巧,其中较为常见的是随机化算法。所以玩提答可以合法浪费时间。
对于这道题,我们先转换模型,找出所有的美丽串,将美丽串作为点,相互冲突的美丽串之间连边,那么问题直接转化为一般图最大独立集问题,直接模拟退火即可。
这里阐述一下模拟退火的原理:
考虑我们现在有一个解,对这个解做出随机的修改,如果这个解比我们的最优解要优秀,那么我们一定保留,如果这个解要屑一些,我们以一定概率保留。
实现上,设置常数 \(k\),变化量 \(\Delta\),终点 \(E\),维护初温 \(T\),每次作出修改时,设解的变化量为 \(\Delta f\),\(T=T\times \Delta\),而上述的一定概率就等于 \(e^{\frac{-\Delta f}{kT}}\)。
而模拟退火的麻烦点就在这里,上述设置的对程序的运行有着大量的影响,所以我们需要调参。
套用到一般图最大独立集问题中,我们先预先求出一个独立集,然后我们考虑修改,每次尝试将一个点加入并求合法独立集,最后比较这个解与我们的最优解即可。
CF R 562 Xor Permutations
你看这个构造,真是太逊了!才乱搞几下就 A 了。
方便起见,设 \(n=2^k\)。
先证明,有解当且仅当 \(\oplus^{n}_{i=1} a_i=0\),证明如下:
- 由 \(p_i\oplus q_i=a_i\),得 \(p_1\oplus q_1\oplus p_2\oplus q_2\oplus\ldots\oplus p_{n}\oplus q_{n}=\oplus^{n}_{i=1} a_i\)。
- 因为异或具有交换律与结合律,得 \(\oplus^{n}_{i=1}p_i\oplus \oplus^n_{i=1}q_i=\oplus^n_{i=1}a_i\)。
- 又因为 \(p,q\) 均为排列,所以 \(\oplus^n_{i=1}p_i=\oplus^{n}_{i=1}q_i=0\)。
- 所以有解当且仅当 \(\oplus^n_{i=1}a_i=0\)。Q.E.D.
接下来考虑如何构造,考虑调整算法:
图源自邓明扬的论文,在参考资料中有提到。
考虑将每个 \(a_i\) 与一个 \(0\sim n-1\) 之间的常数匹配,匹配到 \(a_i\) 的作为 \(p_i\),由于 \(p_i\oplus q_i=a_i\),所以 \(q_i=a_i\oplus p_i\)。
每次我们随机一个未匹配的 \(p_i\),检验是否有能直接与 \(p_i\) 匹配的 \(a_i\),如有,直接匹配,如果没有,随机选取一个未匹配的 \(a_i\),断掉异或值等于 \(p_i\oplus a_i\) 的匹配,切换成 \(a_i\) 与 \(p_i\) 的匹配。
笔者在测试自己的一份代码时,发现这个乱搞相当得快,目前也无法证明这个算法的时间复杂度、正确性(邓明扬,IOI2021 AK 选手,都证明不出这玩意,我何苦为难自己?)。
CGR 12 C Errich-Tac-Toe
这玩意与传统的井字棋规则相比,少了一个对角线,且只要连续三个一样就能赢。
在构造题目中,遇连续多少个就要想到染色,类似的,在这题中,对于格子 \((x,y)\),按 \((x+y)\bmod3\) 分类,显然为了平局,只需要将连续的三个格子没有相同颜色即可。
类似的,我们有如下 \(6\) 种方法来达成目的:
- 第一类格子全改为
X
,第二类格子全改为O
。 - 第一类格子全改为
X
,第三类格子全改为O
。 - 第二类格子全改为
X
,第一类格子全改为O
。 - 第二类格子全改为
X
,第三类格子全改为O
。 - 第三类格子全改为
X
,第一类格子全改为O
。 - 第三类格子全改为
X
,第二类格子全改为O
。
然而这还有个操作限制 \(\lfloor\frac{k}{3}\rfloor\)。但是我们发现这六种方法的操作数总和是 \(2\times k\),依据鸽巢原理,最少的一份最多有 \(\lfloor \frac{k}{3}\rfloor\),选取最少操作步数的一种方案即可通过本题。
WF 2014 Baggage
As a resault,nobady solved this problem during the WF 2014:)
首先这个题有别于我们之前所讲的构造,他要求最优解,然而我们连最优解的答案是什么都不知道,而且这题好像也没别的什么性质。
考虑先爆搜抑或是手玩,于是你发现一个关键点,这个最优解在一定的小范围内是 \(n\),其实我们可以估计出一个答案的下界:
- 设相邻的两个字母不相同的对数为 \(d\),那么一开始 \(d=2\times n-1\),目标状态 \(d=1\),这之间的变化量为 \(2\times n-2\),每一次操作最多使得 \(d\) 减掉 \(2\),但第一次操作无论如何 \(d\) 都只会减掉 \(1\)。
- 所以答案的下界为 \(1+\lceil\frac{2\times n-3}{2}\rceil=1+n-1=n\)。
注意观察爆搜出的解,当 \(n>3\) 时,在结束时所有的货物均在 \(-1\sim 2\times n -2\) 处,这启示我们特判 \(n=3\) 的情况,处理剩下的情况,将大问题规约到子问题。
这种方式是这样的:
__BABABABA…BABABA
ABBABABABA…BAB__A
ABBA__BABA…BABBAA
此刻我们发现,中间的 __BABA…BA
是一个子问题,递归下去做。
ABBAAAA…BBB__BBAA
A__AAAA…BBBBBBBAA
AAAAAAA…BBBBBBB__
至此,我们便完成了构造。
具体实现方向是,将 \(n=3,4,5,6,7\) 的情况进行打表,按上述方式递归即可。
CF R 649 Ehab's Last Corollary
考虑建立出 DFS 树。
因为这是一张无向图,所以他的非树边一定是后向边,那么在 DFS 的过程中,如果遇到了非树边 \((u,v)\),满足 \(|dep_u-dep_v|< k\) 时,从 \(u\) 到 \(v\) 的树上简单路径上的点可以构成一个大小不超过 \(k\) 的简单环。
接下来考虑找不到简单环的情况,方便起见,设 \(lim=\lceil\frac{k}{2}\rceil\)。
- 若 \(m=n-1\),也就是原图是一棵树,考虑将节点按深度奇偶性分类,显然在同一类的点是一个独立集,而我们分成的这两个集合总大小为 \(n\),依据鸽巢原理,较大的那一份至少为 \(\lceil\frac{n}{2}\rceil\ge lim\) 个,直接对这一份乱取 \(lim\) 个即可。
- 否则,说明这张图上不存在一条非树边满足 \(|dep_u-dep_v|<k\),也就是说,对于距离在 \([2,k)\) 之间的点对,不存在有边相连,那么,我们取深度最深的那个点,他的深度一定 \(\ge k\),取他与他的 \(2,4,\ldots,2\times lim-2\) 级祖先作为独立集一定是满足条件的。
CF R 628 Ehab's Last Theorem
这题和上题是同一个出题人
为了下面方便讨论,设 \(lim=\lceil\sqrt{n}\rceil\)。
建出 DFS 树,同上题,如果在遍历中出现了后向边 \((u,v)\) 且 \(|dep_u-dep_v|\ge lim-1\) 时,自 \(u\) 到 \(v\) 的树上简单路径上的点可以构成一个简单环。
如果没有环,按照 \(dep_u\bmod (lim-1)\) 的值来分类,对于一对在同一类的,呈父子关系的点,他们的树上简单路径距离一定 \(\ge lim-1\),而我们在上面已经确定,对于一对这样的点,没有后向边将他们相连,所以同一类的点构成了一个独立集。
依据鸽巢原理,最大的一类里至少包含 \(\lceil\frac{n}{lim-1}\rceil\ge lim\) 个,所以选取最大的一类中的任意 \(lim\) 个点就可以满足条件。
CF R 684 Graph Subset Problem
先考虑至少有 \(k\) 个邻居的子集怎么做,考虑将 \(deg<k\) 的节点塞到一个队列中,每次删点并同时处理相邻点的 \(deg\),当队列为空时,剩下的点就是一个满足条件的子集。
如果上面的子集为空,我们就要考虑判断团,实际上,在做上述的过程时,如果我们遇到一个节点 \(u\),满足 \(deg_u=k-1\),就可以考虑他与他的邻居为一个团,判定方法十分简单,直接暴力枚举 \(\frac {k(k-1)} 2\) 条边,使用 set 或是哈希表判断一下就行了。
SDOI 2019 热闹的聚会与尴尬的聚会
我们先分析这个离了谱的条件:\(\lfloor\frac{n}{p+1}\rfloor\le q\) 并且 \(\lfloor\frac n{q+1}\rfloor\le p\),推导过程如下:
那么,因为题目要求构造的两个集合是独立的,所以分别最大化 \(p,q\) 即可。
最大化 \(p\) 非常简单,将节点按度数排序,每次尝试删掉度数最小的节点 \(u\) 使答案变大,直到图被删空为止,记录所有时刻里 \(p\) 最大的一刻作为答案。
最大化 \(q\) 呢?显然这是一个一般图最大独立集问题,wjr 并不想在年纪轻轻的时候就挑战图灵奖,所以这里只有用模拟退火才能解决了。
问题是否就止步于此呢?我们上述的做法完全没有用到上述两个问题的关联,实际上,在上面的三道题中,都出现了图上两个看似毫不相干的问题的构造,而且这两个构造是有一定关联性的,网上有人称这些问题是“图上二选一构造问题“(见参考资料)。
所以说,我们设计这样一个,由最大化 \(p\) 的做法修改而来的算法:
- 每次选出度数最小的 \(u\)。
- 将 \(u\) 加入第二个点集。
- 删除 \(u\) 与 \(u\) 的邻居。
同样的,记录 \(p\) 最大的时刻作为第一个点集,而在算法最后我们也得到了第二个点集。
正确性呢?我们设第二个点集为 \(E\),显然对于每个度数最小的 \(u\),\(u\in E\),而 \(p=\max\{deg_u\}\),也就是说,每次删去的点数最多有 \(p+1\) 个,共删了 \(q\) 次,所以 \((p+1)q\ge n\),所以满足条件 \((p+1)(q+1)>n\)。
至此,问题得到解决。
IOI 2019 Spilt
三个点集的大小没有关系,我们不妨假设 \(a\le b\le c\),这样方便构造。
容易发现我们只需要分别构造大小为 \(a\) 和 \(b\) 的点集即可,因为如果构造大小为 \(c\) 的点集,其必然可以删掉一些点,转化为大小为 \(b\) 的点集。
算法一:\(m=n-1\)
从部分分出发,我们考虑如何处理树的情况,此时选出的两个联通子集 \(A,B\) 均为子树,所以枚举每一条边,判断这条边左右两边是否存在一个大小不小于 \(a\) 的子树和一个大小不小于 \(b\) 的子树,分别构造即可。
但是,我们仔细分析这题的性质,如果我们取出这棵树的重心 \(C\),那么有解的条件为,将 \(C\) 提为根后,至少有一棵 \(C\) 的儿子子树大小 \(\ge a\)。
如果全部 \(<a\) 的话,集合 \(A\) 与集合 \(B\) 必然有交且交于重心。
所以,我们从上述的儿子子树中选取 \(a\) 个相邻的点,再选取重心与其他子树共 \(b\) 个点,即可完成题目。
算法二:一般图
受算法一的启发,考虑建出 DFS 树,找到 DFS 树的重心 \(C\),去掉 \(C\) ,DFS 被划分成若干子树,设在 \(C\) 上面的子树为 \(T\),剩下的子树分别为 \(S_1,S_2,\ldots,S_k\)。
- 如果 \(T\) 或某个 \(S_i\) 的子树大小 \(\ge a\) 的话,同算法一可以出解。
- 否则,考虑前文提到的无向图上 DFS 树的性质,发现在 \(T\) 和 \(S_i\) 之间可能有连边(后向边),在 \(S_i\) 与 \(S_j\) 之间不可能有连边(无横叉边)。
- 如果 \(T\) 与所有相连的 \(S_i\) 的大小总和 \(< a\),那么一定无解,因为集合 \(A,B\) 一定交于重心。
- 否则考虑处理一个集合 \(X\),初始时 \(X\) 里面包含 \(T\),按任意顺序往 \(X\) 里面添加与 \(T\) 相连的子树 \(S_i\),直到 \(X\) 的大小 \(\ge a\),剩下的节点显然是足够构造出 \(B\) 的,按如下方法构造 \(A,B\):
- 构造 \(A\),先将 \(T\) 加入 \(A\) 中,找出 \(X\) 中所有与 \(T\) 相连的点 \(u_i\),将 \(u_i\) 加入 \(A\) 后,如果仍然不够,考虑将每个 \(S_i\) 里的其他点加入,从 \(u_i\) 开始在子树中 DFS 即可。
- 构造 \(B\),显然重心 \(C\) 是要加入的,然后把不在 \(X\) 中的子树依次加入即可。
CF R 614 Rin and The Unknown Flower
算法一
我会暴力!问一次 C
,问一次 H
,剩下的都是 O
!
费用 \(1+1=2\),显然无法通过。
算法二
事实上问一次 C
是不是太过浪费了呢?我们问 CC
,CO
,CH
同样可以问出除了最后一个位置的 C
,费用只有 \(\frac 3 4\)。
同样的,我们再来确定 O
,为了最大化利用先前的询问,问 HO
,OO
就可以问出除了第一个位置的所有的 O
,费用共 \(\frac 5 4\)。
那么显然在第 \(2\) 个到第 \(n-1\) 个位置中,没有被问来的一定是 H
,而第一个位置,如果没有问出来的话,显然有 O
,H
两种可能,同理,对最后一个位置,如果没有问出来的话,显然有 C
、H
两种可能,共 \(2\times 2=4\) 种可能,询问 \(3\) 个即可。
费用 \(\frac 5 4+\frac 3{n^2}\),可以通过本题
……
……
……的 \(n>4\) 部分。
笔者在写这一段中做了测试,只实现这个做法会 WA On Test 3,因为当 \(n=4\) 时,总费用为 \(\frac 5 4+\frac 3 {16}=1.4375>1.4\)。
算法三
单独处理 \(n=4\) 的情况。
同样的,先询问 CC
、CO
、CH
、HO
,如果有一个成功了,至多有两位没有确定,且前三位没确定的不可能有 C
,至多 \(6\) 种可能,费用为 \(\frac 4 4+\frac 5 {16}=1.3125\)。
如果上述均未成功,再询问 OO
,如成功,有如下可能:
OOOO
,显然可以直接输出。OOO*
,最后一位可能是C
或H
,这是显然的。OO**
,第三位只可能是H
,最后一位可能是C
或H
。
至多 \(2\) 种可能,费用为 \(\frac 5 4+\frac 1{16}=1.3125\)。
如果上述均未成功,那么字符串一定形如 *HH*
,第一位不可能是 C
,最后一位不可能是 O
,询问 HHH
就可以确定字符串,费用为 \(\frac 5 4+\frac 1 9=1.3611\)。
与算法二结合即可 AC。
Technocup 2020 Elimination R3 Not Same
下面,设答案矩阵为 \(b\)。
算法一
从 \(1\) 到 \(n\) 依次考虑每一列,假如现在考虑第 \(i\) 列,按如下方法构造:
- 考虑之前的 \((n+1)\times (i-1)\) 的矩阵,如果某两行相同,设这两行分别为 \(r_1,r_2\),我们使 \(b_{r_1,i}=1\),\(b_{r_2,i}=0\),剩下的 \(a_i-1\) 个 \(1\) 随便乱放。
- 如果没有相同的两行,直接将 \(a_i\) 个 \(1\) 随便乱放。
证明如下:
将相同的行放到一组,记录每个组内行的个数,得到一个可重集 \(S\),初始时 \(S=\{n+1\}\),结束状态 \(S=\{1,1,\ldots,1\}\),共 \(n+1\) 个 \(1\)。
我们对某两行操作的效果,其实相当于选出一个大于 \(1\) 的元素 \(x\),将其拆分成两个元素 \(x_1,x_2\),再丢进集合内。
原集合最多可被操作 \(n\) 次,所以必然可以被构造出来。
算法二
因为列置换不影响答案,所以将 \(a\) 从大到小排序。
对于每个 \(a_i\),从第 \(i\) 行开始放 \(1\),一路往下放,放到底了就循环上去放。
证明如下:
若行 \(i,j(i<j)\) 相同。
因为 \(a_{i+1}\le n\),所以 \(b_{i,i+1}=0\),又因为行 \(i\) 与行 \(j\) 相同,所以 \(b_{j,i+1}=0\),所以 \(a_{i+1}\le j-i-1\)。
如果 \(i+2\le j\),考虑第 \(i+2\) 列。要么 \(b_{i,i+2}=b_{j,i+2}=0\),要么 \(b_{i,i+2}=b_{j,i+2}=1\),如果是后者,那么 \(a_{i+2}\ge j-i+1\),又因为我们从大到小排了序,\(a_{i+1}\ge a_{i+2}\ge j-i+1\),与前文不符,所以 \(b_{i,i+2}=b_{j,i+2}=0\),所以 \(a_{i+2}\le j-i-2\)。
类似的,我们可得 \(\forall k\in[1,j-i],a_{i+k}\le j-i-k\),当 \(k=j-i\) 时,\(a_{j}\le j-i-j+i=0\),与题意不符。
CGR 8 Ski Accidents
\(\frac 4 7 n\),诡异的标点个数,我们不如思考一下,这个 \(\frac 4 7 n\) 能启发我们什么,\(1+2+4=7\)?
我们考虑把节点分为三个集合 \(A,B,C\),满足 \(4|A|\ge 2|B|\ge |C|\),那么必然的是 \(|C|\le \frac 4 7 n\),只要把 \(C\) 删除了就满足条件了。
考虑怎样构造三个集合,我们按如下的构造方法:
- \(A\) 里面是所有入度为 \(0\) 的点与所有入边来自 \(C\) 的点。
- \(B\) 里面是至少有一条入边来自 \(A\) 的点,且没有来自 \(B\) 的入边。
- \(C\) 里面是至少有一条入边来自 \(B\) 的点。
由于每个点的出度最多为 \(2\),所以有 \(4|A|\ge 2|B|\ge |C|\)。
而删去 \(C\) 后,唯一剩下的边是 \(A\to B\) 之间的边,所以也是符合条件的。
因为原图是一个有向无环图,所以可以迅速完成划分。
UR 5 怎样提高智商
既然要求正确答案尽可能多,那么显然会有 \(a_i=b_i=c_i=d_i\)。
我们来 xjb 胡一个构造:因为第零题不存在,所以 \(a_i=0\),\(h_i\) 乱取,这显然四个都可以选,我们假设选了 A
,那么第二题问什么比较好?A
有 \(1\) 个?那第一题只能选 A
了;A
有 \(0\) 个?那第一题可以选 B
、C
、D
三种选择,是不是要好一些。
以此类推,所有问题都形如 \(c\) 有 \(0\) 个,其中 \(c\) 是随便一个字符,此时的答案总数为 \(4\times 3^{n-1}\),可以证明这是最优的。
UER 8 打雪仗
算法一
我们的操作步数够多!我们直接让小 A 把整个序列发过来。
期望得分:\(20\) 分。
算法二
考虑将原本的 \(01\) 串三等分,那么必然有一段含小 B 需要的元素达到半数,我们让小 A 把这一段全丢过来。
那么剩下的两段,我们就让小 A 只把小 B 需要的元素丢过来。
那么,小 B 需要传送 \(\frac 4 3 n\) 的信息,小 A 最多需要传送 \(\frac 2 3 n+\frac 2 3 n=\frac 4 3 n\) 的信息,可过。
期望得分:\(100\) 分。