【题解】UESTC-XCPC集训队2023年9月招新赛 第二场

比赛链接:Link

为避免 MyGO!!!!! 污染,以下均采用原题头。

按个人感官难度排序,及其主观。

题选的相当棒,值得反复品味。

B. Hello, ACMer!

题意:统计给定字符串中 hznu 的出现次数。

模拟即可。

记得特判字符串长度小于 \(4\) 的情况。

C. New String

题意:给定一个自定义字典序排序规则以及若干字符串,求字典序第 \(k\) 小的串。

\(1\le|S|\le 1000\)

std::map 还原字典序或自定义 std::sort 排序规则均可。

L. Klee's Wonderful Adventure

题意:平面直角坐标系上有 \(n\) 个点,相同第 \(i\) 象限间点的移动速度为 \(v_i\),不同象限间点间的移动速度为 \(v_0\),求从起点 \(s\) 到终点 \(t\) 的最短时间。

\(1\le n\le 3\times 10^3\)

注意到 \(n\) 很小,直接预处理出通过任意两点所需的时间,再跑 dijkstra 就行了。

时间复杂度 \(O(n^2)\)

D. Check Problems

题意:有 \(n\) 个人查验题目,第 \(i\) 个人在第 \(j\) 秒会查验编号为 \(a_i+j-1\) 的题。\(q\) 次询问,每次问第 \(t\) 秒时有多少道题目已经被查验。

\(1\le n,q\le 5\times 10^5\)\(1\le a_1 \le a_2 \le \dots \le a_n \le 10^{18}\)\(0\le t \le 10^{18}\)

相当于数轴上 \(n\) 个点,每个点每次向右扩张一个单位。

那么当一个点触到离它右边的一个点时,往后它就没有贡献了。

并且当一个点没有贡献时,间隔比它小对应的点也都没有了贡献,符合单调性。

因此我们把每个点间的间隔距离 \(a_i-a_{i-1}\) 记录下来,排序,记录前缀和,再在上面二分。

每次查询总是前缀和 \(+\) 没有扩张完的剩下段。

时间复杂度 \(O((n+q)\log n)\)

E. Tree Problem

题意:给定 \(n\) 个点的树,\(q\) 次询问每次询问一个点 \(x\),问树上有多少条简单路径途径点 \(x\)

\(2\le n \le 10^5\)\(1\le q\le 10^5\)

简单画个图,经过 \(x\) 的简单路径的数量就是 \(x\) 所有子树大小的两两乘积。

由于每个子树算了两遍,贡献要除以 \(2\)

别忘记 \(x\) 作为简单路径端点的 \(n-1\) 种情况。

时间复杂度 \(O(n+q)\)

G. Subarrays

题意:给定长度为 \(n\) 的正整数序列 \(a\),求满足子段和为 \(k\) 的倍数的子段数量。

\(1\le n \le 10^5\)\(1\le k,a_i \le 10^9\)

\(sum\) 为前缀和,即求满足 \(sum[l,r]\equiv 0 \pmod k\) 的区间个数。

即: \[sum[l,r] \bmod k =(sum[r]-sum[l-1])\bmod k = 0\] 也就是: \[sum[l-1]\equiv sum[r] \pmod k\] 于是题目变成了对每个位置 \(i\) 求小于 \(i\) 的所有前缀和中有多少模 \(k\) 值相同,用 std::map 维护即可。

时间复杂度 \(O(n\log n)\)

F. Easy Problem

题意:\(A,B\)\(n\times n\) 的网格图上游走,每次移动它们能选择上下左右四个方向中的一个,然后两个人按该方向行走一格(如前方是边界或障碍物则不移动),问两人相遇所需的最小移动步数。

\(2\le n \le 50\)

只要想到把两个玩家的位置同时压缩成一个状态就迎刃而解了。

\(dep[ax][ay][bx][by]\)\(A\) 在点 \((ax,ay)\)\(B\) 在点 \((bx,by)\) 时两人相遇所需的最短步数。

广度优先搜索,每次移动若新位置对应的状态非 \(0\),则代表有更短的路径到达那个位置。

那么我们不移动,否则步数 \(+1\) 进行转移。

\((ax,ay)=(bx,by)\) 时代表两人到达同一点。

J. IHI's Homework

题意:给定整数 \(s\) 和序列 \(a\),令答案为满足 \(x_1+x_2+\dots+x_n\le s\)\(\forall x_i \ge a_i\) 的序列 \(x\) 的方案数。\(q\) 次询问每次更改 \(a\) 中的一个数,问每次变动后的答案。

\(1\le n,q,a_i \le 2\times 10^5\)\(0\le s\le 2\times 10^5\)

简单排列组合,但我不会数学,这题就显得很难。

将题目转化成球盒问题,有 \(n\) 个盒子和 \(s\) 个球,将无区分的球放进有区分的盒子,可以有空盒,且第 \(i\) 个盒子至少得有 \(x_i\) 个球,每次修改一个 \(x_i\),问方案数。

首先把每个盒子放入 \(x_i\) 个球,剩下 \(t=s-\sum x_i\) 个球可以任意放入 \(n\) 个盒子。

结论:\(n\) 个无区别球放入 \(m\) 个有区别盒子,允许空盒的方案数是 \(C_{m+n-1}^{n}\)

那么答案就是: \[\sum_{i=1}^t C_{n+i-1}^{i}\] 发现对于相同的 \(t\) 答案相同,那么只要预处理出上式的前缀和就可以 \(O(1)\) 回答询问。

时间复杂度 \(O(n+s+q)\)

K. IHI's Magic String

题意:现在有一个空字符串和三种操作,输出 \(q\) 次操作后的字符串。

  1. 把一个指定小写字母插到末尾。
  2. 删除字符串末尾的字符(若为空字符串则不操作)
  3. 把目前所有的字符 \(x\) 替换成字符 \(y\)

\(1\le q \le 10^5\)

一般这种正着做简单但时间复杂度高的题总是考虑倒着做。

倒着做的好处在于:假设有操作 \(a\to b\),那么之后添加的 \(a\) 都可以直接用 \(b\) 替代,那如果再有 \(b\to c\) 呢?

\(mp[i]\) 表示在添加 \(i\) 时应该添加 \(mp[i]\),初始 \(mp[i]=i\)

那么对于上面那种情况实际等效于 \(a\to c\),我们直接 \(mp[a]=mp[b]\)

这其实类似并查集的路径压缩方法。

对于删除操作,可以直接用一个延迟标记(这里是 \(\text{del}\)),来 \(O(1)\) 判断当前字符是否计入答案,很妙。

时间复杂度 \(O(q\log 26)\)

I. Optimal Biking Strategy

题意:\(\text{Alice}\) 要去到 \(p\) 米外的超市,他可以走路或骑车。路上有 \(n\) 个停车点,能且仅能在停车点上下车,一块钱最多能骑 \(s\) 米(骑 \(x\) 米需花费 \(\left\lceil \frac{x}{s} \right\rceil\) 元)。他现在只有 \(k\) 元,问最少需要走路多远。

\(1\le n \le 10^6\)\(1\le p,s \le 10^9\)\(1\le k\le 5\)

场上写了一个 \(O(nk\log n)\) 很奇怪的背包一直调不出来,后面发现完全是假的。

感觉我到现在对于 \(\text{dp}\) 一直是模棱两可的状态,很烦。

\(dp_{i,j}\) 代表前 \(i\) 个停车点花费 \(j\) 能骑的最远距离,那么答案就是 \(p-dp_{n,k}\)

至于转移,根据题意算钱要上取整,所以多个相邻的骑车区间肯定是直接合并。

因为连续,所以可以二分,对于每一个 \(k\in[1,j]\) 二分出花费 \(k\) 能骑到的最远距离再转移。

具体地,当前在 \(i\),就从满足 \(a_i-a_l\le sk\) 的最远的 \(l\) 处转移而来,即: \[dp_{i,j}=\max(dp_{i,j},dp_{l,j-k}+a_i-a_l)\] 时间复杂度 \(O(nk^2\log n)\)

H. Ganyu Segment Tree

题意:给定一个长度 \(n\) 初值全为 \(1\) 的序列 \(a\),每个位置有上锁和不上锁两种状态。

三种操作,共操作 \(m\) 次:

  • flip p :改变 \(a_p\) 的状态。
  • mul l r x :把子段 \([l,r]\) 中所有未上锁元素乘以 \(x\)
  • div l r x :查询子段 \([l,r]\) 中所有元素(包括上锁)是否是 \(x\) 的倍数,输出 YesNo 。若为 Yes ,将 \([l,r]\) 中的所有未上锁元素除以 \(x\)

\(1\le n,m \le 10^5\)\(1\le x \le 30\)

修改的数 \(x\) 很小,所以可以把 \(x\) 质因数分解,而 \([1,30]\) 内就 \(10\) 个质数。

我们对每个质数都建一颗线段树,而处理是否能整除只需判断是否该区间都含有某个质因子。

具体的,对于操作 mul l r x,若 \(x\) 能分解成 \(cnt\) 个质因子 \(y\),则在 \(y\) 所属的线段树上区间 \(+ cnt\)

那么对于操作 div l r x,检查 \(x\) 的每个质因子 \(y\),若 \(y\) 所属的线段树在 \([l,r]\) 内的区间最小值比 \(cnt\) 小,那么该区间不能被整除。否则区间 \(-cnt\)

现在考虑如何维护解锁与未解锁。是一个很清奇的技巧:

对于每颗线段树开两个值 \(tr1,tr2\),分别代表当前区间未锁定元素的最小值和区间锁定元素的最小值,初始化 \(tr1=0,tr2=inf\)

对于 muldiv 操作,只对 \(tr1\) 进行操作。

对于 flip 操作,只需单点 \(swap(tr1,tr2)\)

对于查询操作,我们返回 \(\min(tr1,tr2)\)

我们发现 \(inf\) 和加减的值不在一个数量级,相当于没有影响,所以这么做是正确的。

时间复杂度 \(O(m\log n)\)

A. Skills

题意:现有 \(3\) 项技能,编号 \(1,2,3\)。初始每项技能的熟练度为 \(0\)。接下来有 \(n\) 天,第 \(i\) 天可以选择一项技能(假设是第 \(j\) 项)进行练习,然后在这天结束时让这项技能的熟练度增加 \(a_{i,j}\)。同时,如果某一项技能(假设是第 \(k\) 项)已经有 \(x\) 天没有练习,那么在这天结束时,这项技能的熟练度会减少 \(x\)(不会减少到 \(0\) 以下)。

问在第 \(n\) 天结束后,这 \(3\) 项技能的熟练度之和最大为多少。

\(1\le n \le 1000\)\(\forall\text{ } 1\le i\le n\)\(1\le j \le 3\)\(0\le a_{i,j} \le 10^4\)

\(\text{dp}\) 题。

首先要注意到最优解里面,一个技能如果开始学习了,那么中间过程熟练度不会降到 \(0\) 以下。否则不如不学。

其次假如一个技能有 \(t\) 天没有学习,那么将会损失 \(1+2+\dots+t=\dfrac{t(t+1)}{2}\) 点熟练度。

也就是说一个技能如果开始学习了,不会停止学习超过 \(2\sqrt W +O(1)\) 天,其中 \(W=\max (a_{i,j})\)

\(dp_{i,j,x,y}\) 代表到第 \(i\) 天,在这天选择练习技能 \(j\) ,其它两项技能分别有 \(x\) 天和 \(y\) 天没有练习了能带来的最大收益。每次转移从上一天练习的三种情况转移而来。

那么 \(ans=\max(dp_{n,1\sim 3,0\sim W,0\sim W})\)

其中第一维可以滚动,总状态数不超过 \(O(W^2)\)

时间复杂度 \(O(nW^2)\)


【题解】UESTC-XCPC集训队2023年9月招新赛 第二场
https://kisuraop.github.io/posts/f9da5f78.html
作者
KisuraOP
发布于
2023年10月27日
许可协议