2022级5月测试题解
特别感谢华北理工大学、黄冈师范学院、鲁东大学、曲阜师范大学、沈阳化工大学、石家庄铁道大学、中北大学ACM集训队负责人的大力支持。
A 关灯
Tag: 贪心
把 0 变成 1 一定不会让答案变优,因此每次操作只会关掉不超过 k 个连续的 1。
对于每段连续的 1 看看需要几次关掉,最后求和即可。
时间复杂度 O(n)。
B 动物园
Tag: 双指针
如果已知 xl…xr 内的种类数,当 r→r+1 或 l→l+1 时可以通过 O(1) 的时间得到新区间的种类数。因此考虑双指针。
时间复杂度 O(n)。
当然也存在队列的做法。
C 奏绝
Tag: 差分/推式子
解法一:差分
计算区间所有贡献的和,一个很自然的想法是线段树维护区间贡献,每个区间记录该区间内黑白之章往前后的长度和与数量,两个区间合并,跨越区间的贡献即为将某一区间的黑白之章长度和乘另一区间的相反颜色的数量
区间前后缀长度和,区间某种元素的数量,答案的贡献均满足可减性,可以通过差分 O(1) 得出,于是可以利用差分将复杂度优化到 O(n)
本题本来就开了 1s 卡线段树的,zrzring 于心不忍,于是把时间开到了 3s 放了线段树
解法二:推式子
对于给定的任意 l,r(l≤r),不妨仅考虑右端点为 1 的情况,设 f(i) 表示位置 l 到 i 对答案的贡献。
设函数 g0(l,i) 为 l−i 内 0 的下标和, g1(l,i) 为 l−i 内 1 的下标和。
设函数 h0(l,i) 为 l−i 内 0 的个数, h11(l,i) 为 l−i 内 1 的个数。
[sj==0] 为艾弗森括号,如果方括号内的条件满足则为 1,不满足则为 0。
f(i)=j=l∑i[sj==0](i−j)=i∗j=l∑i[sj==0]−j=l∑i[sj==0]j=i∗h0(l,i)−j=l∑i[sj==0]j=i∗h0(l,i)−g0(l,i)
那么区间 l,r 的答案
ans=i=l∑r[si==1]f(i)=i=l∑r[si==1](i∗h0(l,i)−g0(l,i))=i=l∑r[si==1]i∗h0(l,i)−i=l∑r[si==1]g0(l,i)=i=l∑r[si==1]i∗(h0(1,i)−h0(1,l−1))−i=l∑r[si==1](g0(1,i)−g0(1,l−1))=i=l∑r[si==1]i∗h0(1,i)−i=l∑r[si==1]i∗h0(1,l−1))−i=l∑r[si==1]g0(1,i)+i=l∑r[si==1]g0(1,l−1)=i=l∑r[si==1]i∗h0(1,i)−h0(1,l−1)∗g1(l,r)−i=l∑r[si==1]g0(1,i)+h1(l,r)g0(1,l−1)
预处理 4 个数组:
- h[i][p] 表示 1…i 内 p 出现的次数
- g[i][p] 表示 1…i 内 p 出现时的下标和
- sumh[i][p]=∑j=1n[sj=p]∗j∗hp^1(1,j)
- sumg[i][p]=∑j=1n[sj=p]∗j∗gp^1(1,j)
因此最后答案为
ans=(sumh[r][1]−sumh[l−1][1])−h[l−1][0]∗(g[r][1]−g[l−1][1])−(sumg[r][1]−sumg[l−1][1])+(h[r][1]−h[l−1][1])∗g[l−1][0]
单次询问可以 O(1) 得到答案,因此总复杂度 O(n+m)
D 崩坏
Tag: BFS
首先需要bfs求出每个单元格会在何时变为崩坏点,之后再次bfs求出人在逃向终点的途中到达每个能到达的单元格(即为 0 的单元格)的最小时间,与常规迷宫问题相比,其中能否经过该单元格的额外判定条件为:人到达此单元格的最短时间是否比该点变为崩坏点的时间小,小则能够经过,反之不能。
E 下棋
Tag: 贪心
独立的考虑每一个棋子,肯定是能走的时候一定会走,如果说这一步别的棋子走了导致自己不能走了,那就等一会走
贪心,这样一来答案就是每个棋子到 1 号点的距离加上等待的时间,在所有棋子里取最大值
考虑如何计算每个棋子需要等待的时间,这个过程比较困难,如果我们用全局的角度考虑,可以得出一些结论
一个棋子肯定会在某个时刻进入一个连通块,连通块里的所有棋子会连续不断的进入 1 号点,并且连通块会在某些点进行合并,一个连通块的贡献为该连通块首次有棋子进入 1 号点的某个儿子的时刻,加上整个连通块的点的数量
这样的话可以考虑全局瓶颈,因为是能走就走,根据已经推出来的结论,如果我们钦定深度最深的棋子畅通无阻,那么全局的瓶颈肯定是深度最深的棋子所在的连通块
因为 1 号点的特殊性,我们取所有 1 号点的儿子为关键节点,答案是所有关键节点的贡献的最大值
而关键节点的贡献就是,每个节点子树内深度最深的棋子到该关键点的距离加上该棋子所带领的连通块点的数量
由已推出的结论可得这样是正确的,那么这个连通块的点的数量怎么计算呢
首先深度最深的棋子是畅通无阻的,也就是说我们只有该点深度的时间去把别的棋子移到 1 号点使得它不会堵住深度最深的那个点
要考虑整个过程有那些点不属于深度最深的棋子的连通块貌似有点困难,但是时间戳和点是一一对应的,所以我们考虑哪些时间戳会有点出去就好了
于是 O(n) 的复杂度通过此题
思路 1
贪心,能移动一定会移动
考虑对于 1 号点的每个儿子为根的子树进行考虑,显然次数的瓶颈在于深度最深的点,那么先让一个深度最深的点一直移动直到进入 1 号点,之后每个时刻都会有点进入 1 号点了
于是计算一下最深的深度 d,子树内点的数量 c,然后让某一个深度最深棋子畅通无阻得移动到 1 号点,计算这段时间内有棋子出去的时间戳数量,记为 a,一棵子树的贡献就是 d+c−a
然后对 1 号点的所有子树贡献取一个 max 即可,std 使用的是该思路
思路 2
记深度 ≥i 的棋子个数为 cnti,深度 i 的贡献为 cnti+i−1,对所有深度求最大值即可
依旧是对 1 号点每个子树单独跑一边取最大值
题外话 - 动态维护
我们现在换个情景,我们设棋子一旦开始走就不能停,且1号点只有一个儿子,并且支持修改,支持加入一个棋子,删除一个棋子
为了动态维护,这个题的做法基于上述思路就产生了不一样的解释方法
考虑每个棋子所在节点的深度 di,每只棋子钦定一个 ≤di 的到达时刻,并且没有两只棋子的到达时刻相等
记深度为 i 的棋子个数为 cnti,从小到大枚举 i,先往栈里加入 cnti 个棋子,如果栈非空就从栈中弹出一个棋子
可以考虑用线段树维护 ansi 表示考虑时刻 i 后还剩多少棋子,线段树二分查找某个位置后第一次出现连续两个 0 的位置和某个位置后第一个 0 即可
F Put numbers first
Tag: 数论
由于 gcd(i,i+1)=1,因此一种构造方式为让周围的四个数为 Ai,j±1。
考虑对行号分奇偶讨论,对于奇数行输出 1,2,3,…,n,对于偶数行输出 2,3,…,n,1。
时间复杂度 O(Tn2)。
G 三位出题人
Tag: 数学
如果我们画一张 3×n 的表,会发现题目要求等价于,在这张表每个位置填 0 或 1,需要满足每列都不全是 0 且都不全是 1,有 6 放法(23−2),每列相互独立,于是答案为 6n。
zrzring 想出有 k 个出题人的,被 s7win99 制止了,于是就有了这道小清新签到题(实际上 k 个也一样,就是看起来会难一些)。
H 树和路径
Tag: LCA,树形DP
码农题,估计赛时只有巨佬才会开这个题吧,我自己写都要写超过 5 个小时了
记 x 子树内最长链中 x 在原树上的儿子为 x 的重儿子
对于每个询问 x,y 有两种情况,设 x 的深度小于 y:
- lca(x,y)=x,答案就是 x 和 y 之间的距离,加上 x 子树内的最长链和 y 子树内的最长链的长度
- lca(x,y)=x,我们判断一下 y 是否在 x 子树内的最长链上,如果是的话需要在 x 除去重儿子的子树内的最长链,否则找到 x 子树外的最长链即可
I 猫狗争霸赛
Tag: 贪心/二分
解法一:贪心
贪心,因为队伍最多可以有 (n+m)/3 支,但又要保证每个队伍里至少有一只小猫和一只小狗,则答案为 (n+m)/3、n、m 三者取最小值即可。
解法二:二分
不难发现这个问题的答案是有单调性的,因此我们可以直接二分能组成的队伍数量,check 也很简单,即若能组成 x 支队伍则至少有 x 只小猫和 x 只小狗且除去这些小猫和小狗剩下的小猫和小狗的总数也不能少于 x 只。
J 神罚
Tag: 数论
当 n=1 ,即该数只有一位时,该数为 x,直接判断 x 是否为质数即可,当 n>1 时,我们无法确定任何情况下的该数一定为质数,但是可以得知偶数一定合数,且位数大于 1 的个位为 5 的数也一定为合数,至此即可得出结论。
K 雁队
Tag:思维
对原序列差分出来,把区间修改变成单点修改,一字型可以直接得出答案,人字形枚举一个最高点即可
L 关灯
Tag: 二分
如果把 1 和后面的 0 当成一个块,那么每个块的长度呈等差数列,前 k 个块的长度总和为 2k(k+3)。
同时注意到 1 始终为块首元素,因此只需要找不超过 x 的最大的 2k(k+3)。然后判断一下 x−2k(k+3) 是否等于 1。
由于 2k(k+3)=x,那么 k=O(x),可以二分找 k,二分的右边界应取 r=2x 或 r=2e9。
一次时间复杂度为 O(logx),因此总时间复杂度 O(Tlog109)。
如果该题仍然超时,可以考虑使用 scanf 读入或关掉同步,并且将 endl 换成 \n。(这个细节在比赛说明里的选手须知有提到).