PA2021 部分题解
PA 2021 部分题解
「PA 2021」Oranżada
无解条件显然,若 ai 的种类数小于 k,那么输出 −1。
否则贪心的取前 k 个不同的 ai 就好了。
具体细节看代码。
「PA 2021」Od deski do deski
先考虑对于一个固定的序列,判断其是否合法。
设 gi 表示 [1,i] 是否能被删除,那么如果存在一个 j∈[1,i−1] 满足 gj−1=true 且 ai=aj。
也就是说,若一个位置 ai 满足前缀 i−1 是合法的,那么再往后出现 ai 的位置代表的前缀都是合法的。我们称这样的值为特殊值。
于是可以从左到右扫描序列,记录当前前缀的特殊值集合 S,以及当前前缀是否合法。加入一个数时,若前缀合法,则加入的值会成为特殊值。可以通过集合 S 直接判断新前缀是否合法。
接着考虑计数,可以发现计数时不关心特殊值集合 S 具体是什么,只关心它的大小。因为通过上面的方法可知加入的数只关心其是否是特殊值。
记 fi,j,0/1 表示长度为 i,特殊值集合大小为 j,不合法/合法的序列个数。
转移需要分类讨论一下,共四种:
- 当前前缀合法,继续填特殊值依旧合法,并且特殊值数量不会增多。fi,j,1×j→fi+1,j,1。
- 当前前缀合法,但是填不是特殊值的值,那么将变的不合法且特殊值数量增加一。fi,j,1×(m−j)→fi+1,j+1,0。
- 当前前缀不合法,填一个特殊值,那么将变的合法且特殊值数量不会增多。fi,j,0×j→fi+1,j,1。
- 当前前缀不合法,填一个不是特殊值的值,那么依旧不合法且特殊值数量不会增多。fi,j,0×(m−j)→fi+1,j,0。
最终答案为 ∑ifn,i,1。
时间复杂度 O(n2)。
具体细节看代码。
「PA 2021」Zbalansowane słowa
首先对于原题,字符集大小只有 3。
那么就有一种 O(2Σn) 的做法。
枚举字符集,然后构造和为 0。具体的,对于当前枚举的字符集,给前面的几个字母随一个权值,并给最后一个字母的权值设为前面几个字母权值和的相反数。
手写哈希即可做到 O(2Σn),但是我懒用了 map
所以多一只 log,不过没有关系,足以通过原题了。
具体细节看代码。
但是呢,字符集是可以开到 26 的!!!
定义一个字符串的状态为它的字符集,即 aa 的状态为 100⋯0,abd 的状态为 1101000⋯0。
不难发现每个点作为左端点只有 26 种状态,作为右端点也只有 26 种状态。
设当前状态为 S,len=|S|。
给每个字母随一个 ull
范围的权值。
设当前状态的每个字母的权值和为 sum,字符串的权值前缀和为 si。
那么一个区间合法说明 sr−sl−1=r−l+1len×sum。
移项得 sl−1−l−1len×sum=sr−rlen×sum,可以把条件再改一下,设 X 是一个很大的数,则 sum×X+sl−1−l−1len×sum=sum×X+sr−rlen×sum
记 prei 表示 i 前面字符集按最后一次出现的位置排序的顺序,sufi 表示 i 后面字符集按第一次出现的位置排序的顺序。
拿字符串 abbcda 举例。
则 pre4={c,b,a},pre6={a,d,c,b},suf1={a,b,c,d},suf3={b,c,d,a}。
设 fi,j 表示以 i 为右端点,状态大小为 j 的值,gi,j 是以 i 为左端点,状态大小为 j 的值。f 的计算需要用到 pre,g 的计算需要用到 suf。
那么最终就是从后往前枚举,插入右端点的值,查询左端点的值。
具体细节看代码。
「PA 2021」Desant 2
首先有个很显然的暴力 DP,记 fi 表示前 i 个数的答案,sumi 表示 a 的前缀和。
那么 fi=max(fi−1,fi−k+sumi−sumi−k)。
这样复杂度是 O(nQ) 的。
但是可以借鉴一下 这题 的思路。
可以把 DP 的过程看成在图上遍历,当前是否选连出去两条边,k 个点排成一列,可以连成类似这样一张图:
其中横向边的权值是区间和,纵向边的权值是 0。
记特殊边为 2→3,5→6,8→9 这种。
问题变为在图上查询最长路。
考虑分治,若行数不超过列数,考虑跨越中间列的询问一定经过中间列的点,对每个中间列的点求一遍所有点到其和其到所有点的最长路,即可处理这些询问,然后分治下去,复杂度 O(n√n)。
否则,考虑跨越中间行的询问一定经过中间行的点,或者通过至少一条特殊边,对这些点边做一遍上一部分一样的过程即可,然后分治下去,复杂度 O(n√n)。
细节有点多,可以看代码好好领悟。
「PA 2021」Koszulki
简单贪心。
「PA 2021」Pandemia
如果不考虑头部和尾部,那么我们设中间的连续为 0 段的长度分别为 a1,a2,⋯,ak。那么贪心的,我们直接将 a 按照降序排列,然后模拟。
那么如果考虑头部和尾部呢?
继续贪心,显然保护头部或尾部只需一个时间,那么我们在开头就保护。
上述贪心都是基于直觉,也不难证明是正确的(其实我不会证)。
具体细节看代码(自认为写的很丑)。
「PA 2021」Poborcy podatkowi
我们考虑设 fu,i 表示的是以 u 为根的子树,u 留给父亲的链长为 i 的已选边的边权之和最大值。
难点在于转移,考虑以 fu,0 为例,列举我们需要的条件:
- 接到这个点上的长度为 1,3 的链的数量相同。
- 长度为 2 的链的数量为偶数。
可以设 gi,j 表示选了长度为 1 的链的个数减去长度为 3 的个数为 i,长度为 2 的链的数量的奇偶性为 j 时所选边权的最大和。但是发现第一维是 O(n) 的,总复杂度为 O(n2)。
但是有个非常震撼的东西,将儿子序列随机打乱,就可以把第一维控制在 O(√n)。
谁管证明啊(
具体细节看代码。
「PA 2021」Zakłócenia
小清新构造,直觉上尽可能平均分是最优的,也不难证明是正确的。
「PA 2021」Sumy
简单题,显然答案具有单调性,二分即可。
「PA 2021」Mopadulo
设 sumi=(i∑j=1ai)mod109+7,那么 fi 能被 fj,j<i 转移到需要满足以下任意一个条件:
- sumj>sumi 且 sumj 与 sumi 奇偶性不同。
- sumj≤sumi 且 sumj 与 sumi 奇偶性相同。
维护两个树状数组即可。
具体细节看代码。
「PA 2021」Ranking sklepów internetowych
不难发现权值的最大值是 2n+1,计数的话就枚举区间长度,维护一下区间端点的合法区间就可以了。
具体细节看代码。
「PA 2021」Butelki
比较震撼,直接 BFS 即可,因为状态数是线性的。
简单说明一下,考虑一次操作之后,必定有一个瓶子的状态为空或者满了。那么共 6 种情况,对于每种情况,剩下两种瓶子的总量是固定的。所以状态数是线性的。
具体细节看代码。
「PA 2021」Drzewo czerwono-czarne
更加震撼的一题。
先判掉一些平凡的 Case:
- c=c′,输出 Yes
- c 中只有一种颜色,输出 No
- c′ 中,任意 (u,v)∈E 都有 c′u≠c′v,输出 No
前两个 Case 显然。第三个 Case 是由于我们最后一次操作的时候肯定会造出来两个相同颜色的点, 所以不可能没有这样的点对。
然后是最震撼的东西,如果存在一个度数 ≥3 的点,输出 Yes。
因为我太菜,所以我暂时还没有完全看懂证明,所以这里贴一个 Qingyu 大佬的证明。(也可以看官方题解,不过看中文总比看波兰语翻译过来的要好吧。。)
否则原来的树就是一条链啦
- 如果序列开头的元素不一样, 那么我们只能把头给删掉, 因为我们只能
merge
两个连续段, 不能swap
或split
。 - 如果删掉以后,c 的连续段数目 < c′ 的连续段数目就是 No,否则是 Yes。
- 证明仍然是类似的调整。注意到我们总是有一段的长度 ≥2,所以我们一定可以通过伸缩一段让前面一段自由。
时间复杂度为 O(n)。
具体细节看代码。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!