2024-CSP赛前集训总结
Todo List
9.11 😓
190pt。
T1
对 \(n!(1 \le n \le 10^6)\) 进行质因数分解。
Solution
- 赛时
直接枚举 \(1 \to n\),暴力 \(O(\sqrt n)\) 质因数分解。时间复杂度并不优越,理论 \(O(n \sqrt n)\),实测 457 ms,大概 \(O(n \log \log n)\)。
玄学算法建议算一下时间复杂度再交,可以多拍几组数据。
- 题解
A. 预处理出每个数的最小质因数,\(O(\log n)\) 分解。
B. 埃氏筛考虑每个质数的贡献,显然 \(p\) 的贡献为 \(1\),\(p ^ 2\) 贡献依然为 \(1\)(容斥),依然是 \(\log\) 级别的。
T2
求树上最多不相交路径,\(n \le 2\times 10^5\)。
- 赛时
口胡了一下转 dfn + 序列贪心,做不了一点。
然后开始转 DP,易发现 \(f_i\) 表示以 \(i\) 为根的子树内的答案。
显然需要数据结构维护树上单点修改+链求和。
A:数链剖分
B:DFS 序+数据结构维护
LCA 调了我将近 1h。
都不会不如写暴力。玄学评测机跑了 90pt。
没有正解直接交暴力,不要浪费时间
- 赛后
显然,赛时脑抽了。可以发现此类问题可以转换成子树修改 + 单点查询,转 dfn 变成区间修改单点查询直接秒了。
要善于转化问题,比如单点修改区间查询问题可以转换成区间修改单点查询。树上问题最方便的就是子树修改 + 子树查询。
3.题解
首先有一个性质:如果一条链选了,那么以这条链的 LCA 为根的子树里的点都不能选了,因此可以从下往上考虑。
显然这非常可以贪心。直接从下往上考虑,能选就选。
因为每个点最多只会被标记一次,因此为 \(O(n \log n)\)。
多推性质,不要忙于解决问题。
T3
给定一个 \(n(1 \le n \le 25)\) 点 \(m(1 \le m \le 500)\) 边的有向图,每条边都有边权 \(w(1 \le w \le 15)\)。初始时你的价值 \(c\) 为 \(0\)。经过每条边可以选择 \(1\) 个时间单位通过或 \(2\) 个时间单位通过并把 \(c = c | w\)。求从点 \(1\) 出发经过 \(T\) 个时间单位回到 \(1\) 且价值变为 \(15\) 的方案数。
- 赛时
无。
- 题解
矩阵快速幂。
如果直接 DP,那么矩阵的大小为 \(2 * 50 * 15\),达到了惊人的 \(1500\),显然不可取。
考虑容斥,用总的方案数减去某种材料没经过的方案数。
正难则反。
T4
给定 \(n\) 个左开右闭区间 \([l,r)\),要分成 \(k\) 组,要求每组的交集非空。求这 \(k\) 组交集长度之和的最大值。
1.赛时
以为是贪心 or 构造,方向错了,推到比赛结束后都没有推出来。
2.题解
可以把人分为两类(A:包含别人;B:不包含别人)。
A 类的元素可以单独成为一组或者加入它包含的人的那一组。
问题转换为求出 B 组分走 \(k\) 组之后的最大值,显然可以用 DP 来求。
此时可以把 B 中的元素按照 \(l\) 排序,显然此时 \(r\) 也是从小到大排序的。
则此时最优分组一定是连续的。可以构造证明。
\(f_{i,j}\) 表示 B 组中前 \(i\) 个元素用了 \(j\) 组的最大值。
显然,可以使用单调队列优化。
9.16 😫
T1
给定 \(n\) 个 \(1\) 到 \(m\) 之间的整数 \(a_i\),你可以把三个编号相等或者三个编号连续的分为一组。求有多少组分组方案(组和整数都没有编号)。
数据约束:
- 赛时
DP。把 \(a\) 分类。显然,不相连的一块可以看作是独立的。再者,我们可以通过预处理把同一块内的元素全部推平成 \(3\) 的倍数。如果此时有元素小于 \(0\) 或者依然不是 \(3\) 的倍数,则 \(ans = 0\)。
接下来可以把 \(a\) 中元素除以 \(3\),每次操作就等价于把相邻三个元素减去 \(1\)。
一直死磕 \(n ^ 2\) DP,结果假了,只剩下 30min 了。。。
- 赛后
这道题正解就是 \(n ^ 2\),因为 \(n_{max} = 30000\),因此常数够小就能过。
状态设计成 \(f_{i,x,y}\),表示位置 \(i\) 最后两位为 \(i,j\) 的方案数。转移很容易推,就省略了。转移的过程可以用前缀和优化掉,状态可以用滚动数组减少 \(1\) 维。
时间复杂度:$\operatorname{O}(5000 * 5000 * 2 \approx 5 \times 10^7) $,十分优异。
T1 不仅赛时调了我 \(3\) 小时,赛后调了一下午。绷不住了。
9.22 😣
T1
1. Statement
给定正整数 \(n\),计算 \(n\) 个元素的集合 \(\{1, 2, \dots, n\}\) 所有非空子集和的乘积取模 \(998244353\) 后的结果。
2. 赛时
5min 推出正解,然后唐了,《\(a^b = a ^ {b \bmod p}\)》。一个小时时间直接没了,心态爆炸。
其实就是枚举子集和 \(s\),通过 DP 求出凑出 \(s\) 的方案数,注意 \(f\) 数组需要写高精度。
3. 题解
欧拉函数求得 \(f\) 可以对 \(p-1\) 取模。
T2
1. Statement
有 \(n\) 栋楼,每栋楼有 \(k\) 房子。\(m\) 个询问,每次询问给定 \(x,y\),表示这 \(y\) 个人要分配到 \([x, x + d]\) 栋楼中(\(d\) 是定值)。对于每次询问都需要输出能否成功分配。询问之间会相互影响。
2. 赛时
基本上所有时间都花费到这道题上面了。根据显然的贪心可以得出把所有限制按照左端点排序。能尽量往左排就尽量往左排。然后接下来就在想怎么用线段树维护。可以维护,但是非常难写。
3. 赛后
设 \(a_i\) 表示当前左端点为 \(i\) 的线段的数量。
思考一下分配不了的必要条件:必定有一个区间 \([l, r]\) 满足 \(\sum_{i = l}^{r} a_i > k(r-l+1+d)\)。证明这个条件为充分条件:按照之前所述的贪心可以把所有限制排成若干个首尾相连的线段,则必定存在一个区间使得区间内的限制和大于区间内的容量。
设 \(s_i = \sum_{i=1}^{i} a_i - ki\),则可以分配时一定满足 \(s_r - s_l \le kd\)。
显然可以用线段树维护。
T3
T4
1. Statement
给定一个包含 '01?' 序列 \(a\),相邻的任意 \(11\) 可以随便移动,求最终序列的方案数。
2. 赛后
DP。设 \(f_{i,j,k,0/1}\) 表示前 \(i\) 为填了 \(j\) 个 \(11\),\(k\) 个 \(0\),并且 \(i\) 是否可以在后面接一个 \(1\) 变成 \(11\)。
最后对于每种 \(f_{n,i,j}\),把 \(0/1\) 两种情况加起来乘上 \(\binom{i+j}{j}\) 就好了。
解释一下 \(\binom{i+j}{j}\) 是怎么来的。
- 你发现一个 0 是无法跨过长度为奇数的 1 的连续段的。
- 所以对于序列中的任意两个 0, 中间的 1 的奇数段的数量是一定的。
- 所以答案是 \(\binom{i+j}{j}\)。
9.24 😞
T1
1. Statement
有 \(a\) 个 \(0\),\(b\) 个 \(1\),\(c\) 个 \(2\)。两个人轮流做操作。如果当前没有数可以选或者当前选之后所有数的和是 \(3\) 的倍数,则这个人输了。求先手赢还是后手赢。
赛时没开 long long,证明无论什么题都要对拍或造样例。
2. 赛时
开局 1h 推结论看错题了。以为是每个人单独的和。以后一定要先把题目看清楚再写题。显然初始时只能选 \(1\) 或 \(2\)。一个人选了 \(1\) 或 \(2\),另一个人只能选 \(0\) 或另一个数。再者,\(0\) 无论什么时候选都不会影响最终答案。
T2
1. Statement
对于所有长度为 \(n\) 排列 \(a\),求满足第一个 \(i > a_i\) 的期望(如果不存在 \(i\) 则为 \(n+1\))。
2. 赛时
问题可以转换成对于每个 \(i\),求出所有排列中,\(i > a_i\) 且这个 \(i\) 为第一个的方案数。枚举第 \(i\) 位为 \(j\),则需要满足 \(\forall 1 \le k \le i, a_i \ge i, a_i \not= j\)。赛时急了,没有仔细往下推,以为有什么神秘性质可以直接求。
3. 题解
看来赛时真是唐了,稍微推一下就可以得到下面的式子。对于每个 \(i\) 的贡献为:
T3
1. Statement
设 \(x(x \in \N) = \sum_{i=1}^{n} \text{fib}_{a_i}\),满足 \(\forall i \in [1, n), a_i < a_{i+1}\),则 \(a\) 为 \(x\) 的唯一斐波那契分解。
定义 \(val(x)\) 表示 \(\oplus_{i=1}^{n} \text{fib}_{a_i}\),现在给定 \(m\) 次询问。每次询问给定 \(l,r\),求 \(\oplus_{i = l}^r val(i)\)。
2. 赛时
Joker 了。前两题花了太多时间,只够打个前缀和暴力。
3. 赛后
推了一下发现有一种做法是枚举求出第 \(i\) 位在 \([l,r]\) 中出现的次数。不太好做。
然后把斐波那契联想成二进制发现这类题最好做的方法就是 数位 DP。设 \(f_i\) 表示 \(\oplus_{i=1}^i val(i)\),找到最高位的值 \(j\),则 \(f_i = f_{j-1} \oplus f_{j \to i}\),观察到 \(f_{j \to i}\) 中的每一个数都带有 \(j\),因此
显然,斐波那契数列的增长是 \(\log\) 级别的。
T4
1. Statement
给定 \(n,m\) 和长度为 \(n\) 的数组 \(a\),表示有 \(n\) 种面值的货币。每种货币有无数张。求 \([1, m]\) 中最大的不能被凑出来的数。
2. 赛时
依然是没有时间,T3 时间都不够了,更别说 T4 了。
3. 赛后
完全背包可以水过大部分分,加了 bitset 卡卡甚至能水过去。
显然题目中的随机性是非常重要的性质。可以设置一个模数 \(mod\),跑一遍同余最短路。\(mod\) 是越小越好。如果一个数 \(x\) 凑不出来,则答案更新为 \(x\);如果 \(x\) 凑得出来,则答案更新为 \(x-mod\)。
随机数据中一个小数为 \(\frac{m}{n+1}\),时间复杂度为 \(\operatorname{O}(\frac{m}{n+1} \log^2 n)\)
9.25 😵
T1
1. Statement
给定一个长度为 \(n\) 的数组 \(a\),如果 \(i \in [2,n-1],a_{i-1} > a_i, a_i < a_{i+1}\) 则定义 \(a_i\) 为低谷点。你可以把至多 \(k\) 个值减小,求操作之后的最大的所有低谷的和。
2. 赛时
先推性质。显然如果前面操作之后,那么这个点再操作一定不是最优的。看到数据范围果断放弃贪心选择 DP。调了 30min 还是调了出来,整体节奏还是可以的。
T2
1. Statement
给定一个长度为 \(n\) 的数组 \(a\)。进行 \(n - 1\) 次操作。设每次变换之后的 \(a\) 为 \(a'\) ,第 \(T\) 次操作具体如下:
显然,所有操作之后 \(a\) 将只有一个元素,求这个元素。
2. 赛时
观察到最终答案对应 \(a\) 中每个元素的系数一定与杨辉三角有关,这很容易感性理解。但数学知识储备不够多,没有推出来通项公式。中途尝试使用矩乘,显然不可行,2h 浪费了。
3. 赛后
如果 \(n\) 是奇数,则每一项的系数为 \(\sum_{i=0}^{\frac{n-1}{2}} C^2_{\frac{n-1}{2}} \times (-1)^i\)。如果为偶数,则操作一次之后可以变为奇数。
T3
1. Statement
\(2^n\) 个人打淘汰赛,编号为 \(1\) 的人初始时收买了 \(m\) 个人。每场比赛都会让编号更大的人赢,但是 \(1\) 遇到被他收买的人他会赢。求有多少种排列方式使得 \(1\) 能赢且中途打比赛遇到的人构成的序列的最长上升子序列长度 \(\ge k\)。
2. 赛时
DP。时间不太够了,没有仔细推。打了暴力还挂了。
3. 赛后
枚举 LIS 作为状态进行 DP,详见代码。
T4
1. Statement
题面过于复杂,见原题面。
2. 赛后
大模拟先攒着,之后补。
需要暴力出所有的五元组,然后把这些五元组排序,以及存一下每个三元组,可能构成哪些 \(rank\) 的五元组。写完以后对于每组询问,就直接在对应的三元组里面二分就好了。
9.27 😰
0 + 0 + 0 + 30 = 30pt
T1
1. Statement
给定一个长度为 \(n\) 的数组 \(a\),你可以按任意顺序排列这个数组,求是否有一种排列方案使得拆分数组 \(d\) 不存在元素 \(x\),如果有,则输出方案。
2. 赛时
构造。想了一会发现可以分讨,先讨论 \(x = 0\) 的情况,发现同一种元素中需要插空插其他元素,很容易就可以把不合法的情况判掉。需要注意的是,如果第一个数是 \(0\),则需要把第一个数换掉。
如果 \(x < 0\),直接从小到大排,赛时没看到 \(x\) 为非负数,还讨论了一下第一个数是负数的情况。。。
如果 \(x > 0\),从大往小排,如果第一个数为 \(x\),则需要与后面的数交换。
细节比较多,没有注意就会全挂掉。
3. 赛后
\(x = 0\) 的情况赛时准备写链表的,后面发现可以用 vector,但依然比较复杂。这是一类比较经典的模型,每两个元素相消,可以使用 优先队列 来做。每次把出现次数最多的元素排出去, 正确性显然。
一定要对拍啊。不然很容易挂分的。
T2
1. Statement
给定一个 \(n\) 点的树,每个点有一个点权 \(a_i\),定义 \(\operatorname{happy}_{s,t}\) 为 \(s\) 到 \(t\) 的简单路径上的最大点权减去边数,求 \(\sum_{s \not= t} \operatorname{happy}_{s.,t}\)。
2. 赛时
显然可以把问题分成减边数和加最大值这两个子问题。前一个子问题非常轻易的就可以做到。
赛时尝试过枚举一条路径上深度最浅的点,不好算;也试过枚举路径的起点做换根,也不好算。推出来了每个点有一个 作用域 但是不知到怎么去维护它。。。最后只好打了个暴力,还是想复杂了,写了在线查询的,没想到可以直接 \(n\) 便 DFS,不出意料的挂了。
3. 赛后
我是什么品种的废物啊 \(\texttt{QWQ}\)。其实可以把点权排序,如果从大到小排序,就变成了删边求联通块大小,不好做。如果从小到大排序,就变成了加边求连通块大小的问题,可以用并查集轻易的解决。
多从几个方面去想,这道题涉及到了 \(\max\) 自然而然地就应该想到排序。不要觉得题目难做法一定就难。
T3
1. Statement
给定一个长度为 \(n\) 的只包含 NOIP? 这五个字符的字符串。对于每个 ? 你可以填入前四个字符中的任意一个。接下来会给你一个 \(4 \times 4\) 的矩阵,对应着相邻两个字符所代表的权值。一个字符串的价值就是任意相邻字符的权值之和。求所有权值 \(\le x\),按字典序降序排列第 \(k\) 大的解。
2. 赛时
现在看到这类状态数量很大的就认为是 DP 了,看到 DP 就有点 ptsd 了。以为又要花很多时间,跳过去了。其实就算给我那么多时间我也想不到可以用搜索来解决这道问题。
3. 赛后
刷新了我对搜索的认知。
其实搜素只要剪枝得当,时间复杂度就会从指数调到正解。就类似于暴力 DFS 与记忆化搜索的区别。在这道题中,因为 \(k\) 很小,所以可以直接按照字典序从大到小,把所有合法的答案搜出来。如果当前答案不合法,就直接剪掉。至于怎么判合不合法,只需要当前状态往后填的最优价值 \(\le x\) 就行了。当然不可能对于每个状态都做一次 DP,因此可以从后往前预处理出每一位选每个字符的最大权值。搜索时记录出当前的权值,加起来判。时间复杂度是优异的 \(\operatorname{O}(nk)\)。
你说得对,但是这其实就是广义上的 A* 算法。
T4
1. Statement
给定一个长度为 \(n\) 的字符串 \(s\),求 \(s\) 所有子串的所有 border 的长度之和。
2. 赛时
如果直接暴力写 KMP,显然是过于暴力的。发现这道题本质上就是在求每个子串的出现次数,不会 SAM,SA 也没学懂,只能通过 Hash 莽了 30pt。
3. 赛后
对于 SAM 来说,这道题就是板子。对于 SA 来说,可以利用 \(height\) 数组来模拟。从左往右看,就是一个区间不断分分分的过程,但是区间并不均匀,不好做。但是如果从右往左看,就变成了区间合并问题,可以使用并查集来做。
9.29 😕
70 + 90 + 0 + 0 = 160pt
T1
1. Statement
有四盏灯,在一个四方格内。你可以调节每一盏灯的耗电量,每一盏耗电为 \(x\) 的灯可以为当前位置提供 \(x\) 的亮度,为旁边两格提供 \(\lfloor \frac{x}{2} \rfloor\) 的亮度,为对角线的格子提供 \(\lfloor \frac{x}{4} \rfloor\) 的亮度。现在给定每个格子最低的亮度要求,求四盏灯最低的耗电量之和。
2. 赛时
一开始推式子,天真地以为可以 \(O(1)\) 算。显然不好算。看到数据范围选择 \(n ^ 2\) 枚举。又试了一下能不能再直接 \(O(1)\) 算,显然不行。尝试了一下里面套个二分检验,觉得是三分,常数太大了,且不好写。已经浪费较多时间了,选择 \(n^3\) 暴力然后开下一题。
3. 赛后
赛时只要往三分的方向去想,就输了。以后做这类数学题,一般要主动往有单调性的方向去想。比如这道题,就完全没必要去对一盏灯的亮度去考虑。而是可以直接二分总耗电,然后去检验合法性。检验可以直接 \(n ^ 2\) 枚举对角线两盏灯的耗电,此时这个不等式就变成了一元不等式。因此可以求出其中一盏灯的大约范围,直接枚举取最小值就行了。
此外,还有一种做法。当枚举对角线的两个点时,会发现它很具有连续性,因此每次剩下两盏灯的波动并不会太大,这种做法比上一种做法优异很多。
T2
1. Statement
给你一个 \(n\) 点的树,每个点上都有一个带有权值的蚂蚁,每个蚂蚁可以留在原地或者向上爬到父亲,且最多只能爬一次(位于节点 \(1\) 上的蚂蚁只能留在原地)。当所有蚂蚁都爬过之后,每个点上的权值为:如果当前点的蚂蚁数量小于等于 \(1\),则这个点没有贡献;否则贡献为这个点上所有蚂蚁权值的异或和。求所有情况的权值和。
2. 赛时
一眼 DP。设 \(f_{i,0/1}\) 表示以这个点为根的子树的所有情况中这个点的蚂蚁上不上去的价值和。转移很好像,把 \(f\) 和蚂蚁的贡献分开来求。对于蚂蚁的贡献来说,可以从二进制位的方面去考虑。思路比较简单,但是细节较多,调了我好久。
3. 赛后
其实这道题正解可以算是递推或者组合数学,赛时做法过于复杂了。
T3
1. Statement
你有 \(n\) 个字母 A,\(m\) 个字母 B。每连续 \(a\) 个 A,且下一个依然是 A,则价值会加上一。每连续 \(b\) 给 B,也同理。当这个字母与前面一个字母不一样时,价值加一。求最大价值。
2. 赛时
真的写 DP 写到 ptsd 了,看什么都是 DP。。。觉得又是什么神秘 DP,选择开下一题。
3. 赛后
很难想象 C 会放比较容易的贪心。其实这道题贪心策略是非常容易想的。显然,交错次数过多,答案相对会更优。但是这个交错次数有一个界限,因此可以枚举这个界限。由于 A 转换到 B 是没有条件的,因此每一组应该被分成 \(c\) 个 B 和 \(1\) 个 A,类似于 BBBABBBA。如果还剩下 A,就往开头填;如果还剩下 B,就往结尾填。还剩下 A,每 \(a\) 个可以加一贡献。还剩下 B,可以先把 \(c\) 填满,再继续填。
T4
1. Statement
有一个函数 \(f(x)\),这个函数有 \(n\) 个步骤,第 \(i\) 个步骤如下:
接下来有 \(q\) 次操作,每次操作要么改变 \(f\) 第 \(i\) 步的 \(op\) 和 \(val\),要么给定 \(x\),求 \(f(x)\)。
2. 赛时
Subtest 2 + 暴力已经想出来了,时间不够了,匆匆忙忙结果写错了🤡。
3. 赛后
路上想出来了 Subtest 3 的二分做法和 Subtest1 堵塞做法,推出来了每一段答案可以表示成一段区间。
通过题解得知,每一个答案不仅可以表示成区间,还要表示成加上某个值。这个操作可以通过线段树维护。
9.30 😭
44 + 20 + 25 + 20 = 109
T1
1. Statement
\(n\) 个点的树,有边权。选择一对点 \((u,v)\),这段路径上的边权极为 \(S\)。A 先手,B 后手。每个人轮流选走一个小于等于上一个数的数。如果当前没有数可选,则这个人输。求有多少对 \((u,v)\) 使得 A 能赢。
2. 赛时
绷不住了,1min 出正解 30min 思考如何求答案,我是什么品种的弱智。。。先思考博弈策略,显然,序列中只要出现一个出现次数为奇数的数,则先手必胜。然后这个东西可以抽象成二进制异或,然后就可以简化成每个点到根节点。考虑容斥,出现不好求,求逆变成所有都为偶数。回到刚才的点到根节点,因为只要两个点异或起来为 \(0\),即连个点所对应的二进制数相同,则答案要减去对应值。
但是这个二进制数有 \(5 \times 10 ^5\) 位,所以很自然就会想到 Hash。但是赛时弱智了,一直想到用数据结构维护。
3, 赛后
除了刚才说的 Hash 做法,还可以使用一种非常新的技巧:随机化。把每个边权赋一个随机值,只需要记录跟到每个节点的异或和就行了。
T2
1. Statement
给定长度为 \(n\) 的序列 \(a\),初始时你在位置 \(1\).你可以跳 \(k\) 次,如果 \(k\) 是奇数,则可以跳到你右边的任意一个格子,否则可以跳到左边的任意一个格子。每次跳跃的价值定义为跳跃时经过的所有点之和。求 \(k\) 次跳跃之后的最大价值。
2. 赛时
DP。看到 \(k\) 很大,要么 \(\log_2\),要么数学。显然 \(\log\) 做法时不可行的。数学有两种做法,一种是循环节,一种是最大子段和。个人认为循环节最有可能,写了。赛后才发现假了。。。
3. 赛后
先说另外一种人类智慧做法,因为 \(n\) 很小,所以可以先处理出前 \(\min({k, T})\) 跳到某个位置的最大价值,然后剩下的就来回跳以 \(i\) 为端点的最大子段和。事实上,\(T\) 只需要取到 \(8\) 就行了。这种做法达到了惊人的 \(\operatorname{O}(N)\)。
对于最大子段和这种做法来说,也是 DP。不过必须先推出几个性质:
-
钦定一个点,在这个点经过若干次跳跃之后,接下来来回跳以这个点为右端点的最大子段和。对于若干个转移来说,时间最小的最优(这并不难证明)。因此转移到这个点的价值就变成了附带属性。
-
如果以这个点为右端点,无论怎么跳,都不会跳到这个点右边。
接下来的转移随便转就行了。
T3
1. Statement
\(n\) 个节点的树,可以把数量位于 \([B, 3B]\) 之间的若干个点分为一个省(这些点不一定联通)。每个省都要确定一个省会 \(y\),一个点可以是多个省的省会。但是对于同一个省里面的任意点 \(x\),都需要满足 \((x,y)\) 路径上点和 \(x\) 在同一个省。给出一种划分方案。
2. 赛时
贪心,赛时时间不够了,糊了一个连样例都没过的乱搞。竟然有 25pt。
3. 赛后
从底到跟去考虑。对于每个点来说,假设它所有的城市个数小于 \(B\) 的子树,利用优先队列把它们合并,这个点作为这些省的省会。此时可能会存在一个省的大小依然小于 \(B\),可以把它与当前这个点划分成同一个省,往上传,就变成了子问题。
对于根节点来说,没法往上传,但是由于此时任意一个省的大小都 \(< 2 * B\),且根节点所属的省的大小 \(< B\),只需要随便找一个合并就行了。
T4
1. Statement
给定长度为 \(n\) 的排列 \(a\),每次操作可以把区间 \([l,r]\) 循环右移 \(k\) 位,求出每次操作之后是否存在上升三元组。
2. 赛时
一直以为是 \(n \sqrt n\) 做法。
3. 赛后
循环右移等同于把一段区间交换,只能使用 FHQ-Treap 来做。需要维护出一个子树内的最大值,最小值,两位的前面最大值,两位的后面最小值。
发现后面两个值并不好维护,因为子树内的值并不具有单调性。可以通过先把 ok 的情况判掉来构造单调性。
10.2 😔
36 + 5 + 80 + 0 = 121pt
这场比赛时间分配真的不好。。。
T1
1. Statement
给以一个 \(n\) 点的树,树上每条边都有一个边权 \(w(1\le w\le10^{100})\),每经过这条边代价就要加上 \(w\),树上有 \(m\) 个初始点和 \(m\) 个终点,每个初始点都要移动到一个终点上,且一个终点只能对应一个初始点。求最终最少的代价。
2. 赛时
本来准备贪心切掉的,每个点移动到子树内最远的点。发现并不好维护,接下来推出两个性质:
- 当出现类似于
A1...B2...B1...A1时必定不是最优的。 A1...A2...B2...B1和A1...A2...B1...B2的代价是一样的。
接下来就有一个更优的贪心策略了:对于子树内的点,如果还剩下多余的起点,就往上移;对于每对起点和终点,随便找一个消掉就行了。
但没必要这么做,可以换一种角度来想,把起点挪动终点相当于把起点和终点都分别挪到它们的 LCA。这时只需要对于同一个节点内的起点终点两两相消。
但是,我赛时因为神秘错误大样例挂了调了 3h 死活调不出来😡,我甚至开始怀疑我贪心的正确性,心态爆炸,后面的题直接寄了。赛后才发现我高精 fill 没清完。这是人能调出来的错误吗。。。
T2
1. Statement
有 \(n\) 种价值的物品,第 \(i\) 种物品的价值为 \(v_i\),出现次数为 \(c_i\)。你每次可以选择两个物品,它们所浪费的价值为 \(m - ((v_i + v_j - 1) \bmod m + 1\)。求最优匹配下的最小浪费价值。
2. 赛时
推了式子,以为是 DP,没有往贪心的方向想。
3. 赛后
其实只要往贪心这方面想,这道题就直接秒了。显然,设一个数浪费的值为 \(b_i\),先不考虑其他情况,无论怎么分配,浪费价值都为 \(\sum{b_i}\)。当 \(b_i + b_j \ge m\) 时,总浪费价值就会减去 \(m\)。这时贪心策略就出来了:尽可能然更多的 \(b_i + b_j \ge m\)。这类题可以直接排序 + 双指针秒了。
T3
1. Statement
\(n\) 个学生,第 \(i\) 个学生的做题数为 \(f_i\),成绩为 \(t_i\),只有当 \(a_j \le t_i \le b_j\) 时且 \(c_i \le t_j \le d_i\) 时,\(i\) 才会帮 \(j\) 完成它的 \(f_i\) 道题。
2. 赛时
没有时间推了,时间给够一定可以推出来。
3. 赛后
显然,这道问题可以转换成 \(t_j\) 在 \([a_i, b_i]\) 这段区间中的 \([c_j, d_j]\) 这些区间中包含 \(t_i\) 的区间个数,这玩意很显然可以前缀和。可以从把所有值离散化,在值域中由小到大枚举。对于每个点记录出它是哪些 \([a_j, b_j]\) 的左端点或右端。枚举的过程中用数据结构维护在区间 \([c_i,d_i]\) 加 \(f_i\),单点查询 \(t_j\)。然后这道题就没了。
T4
1. Statement
给你一个序列和若干个询问,每次询问给出一个区间,求出这个区间所有数字乘起来之后,莫比乌斯函数值,
约数个数,约数和。
2. 赛时
以为有什么神秘性质可以通过线段树维护。
3. 赛后
先攒着,等题过后更新。
10.3 🥴
45+100+0+100 = 245
信心赛考成这样。。。
T1
1. Statement
长度为 \(n\) 的序列 \(a\),每一位可以填入 \([1,m]\) 中的任意整数,对于序列 \(a\) 和 \(b\) 来说,定义它们相同仅当满足 \(\exists k, \forall i, a_i \equiv b_i + k \pmod m\)。求有多少个不同的 \(a\)。
2. 赛时
显然,在不考虑相同的情况下,方案数为 \(m ^ n\)。更显然,每个相同组的大小都为 \(m\),因此答案就是 \(m^{n-1}\)。
3. 赛后
还有一种思考方式,先假设第一位固定为 \(1\),那么接下来的方案数为 \(m^{n-1}\)。此时把第一位的限制拿掉,会发现无论怎么变,都会与之前的相同,因此答案就是 \(m^{n-1}\)。
T2
1. Statement
有 \(n\) 个果园,每个果园有 \(a_i\) 个果子。有两个工厂,每个工厂有 \(b_i\) 个机器。每个果园可以把果子以任意一种分配方式分给两个工厂。设第 \(i\) 个园子给了第 \(j\) 个工厂 \(w_{i,j}\) 个果子,则运输时间为 \(d_{i,j}\),加工时间为 \(u_{i,j}\),如果 \(w_{i,j}\) 不为 \(0\),则需要用掉第 \(j\) 个工厂 \(c_{i,j}\) 个机器。任意时刻都不能让任意工厂机器 \(<0\)。最终所耗时间为 \(\max(w_{i,j} \times d_{i,j}) + \max(w_{i,j} \times u_{i,j})\)。求最小耗时。
2. 赛时
阅读题面花了好久。
因为数据范围很小,先考虑暴搜,发现常熟过大,且 Meet in middle 不好实现,放弃暴搜。
考虑 DP,发现状态数量很大,怕炸空间,且不好优化,放弃 DP,选择开下一题。
回到这一题,发现真正的难点是 \(\max\),考虑枚举 \(T_d\),DP 求出最小的满足条件的最小的 \(T_u\)。发现 \(T_d + T_u\) 近似于单峰函数,选择三分。
3. 赛后
不出意料,赛时挂了 55pt,既有 DP 的锅,也有三分的锅。很容易就会发现,这个函数会出现重复值,就不能用三分。因此只能枚举每个可能的 \(T_b\),二分跳掉重复值。
除此之外,这道题确实可以 DP。设 \(f_{i, b1, b2, j}\) 表示考虑前 \(i\) 个果园,第一个工厂用了 \(b1\) 个机器,第二个工厂用了 \(b2\) 个机器,第一个工厂运了 \(j\) 个果子的最小运输时间。同理 \(g_{i, b2, b2, j}\) 表示同一个情况的最小加工时间。转移很简单,随便转就行了。赛时没考虑到状态数量其实很小。。。
这道题还可以用暴搜做,Meet in middle 肯定可以做的,暴搜加点最优性剪枝也可以过。
T3
1. Statement
有 \(n\) 个位置,\(m\) 个人,每个人加入时会走进离其他人最远的位置,如果有多个,则进入编号最小的。现在有 \(2 \times m\) 个事件,每个事件代表一个编号。当这个编号第一次出现时,代表这个人加入了位置。第二次出现时,代表这个人离开了位置。求每个人加入时他走进的位置。
2. 赛时
一眼 set 维护直接秒了。维护两个 set,分别代表点集和所有的区间。加入操作时,相当于找到在点集中找到前驱后继,删除大区间,加入两个小区间。删除操作时,相当于在点集中找到前驱后继,删掉两个小区间,加入大区间。
另外注意还要考虑两边的情况。细节有点多,90 多行代码调了 1h。
T4
1. Statement
给定一个 \(n\) 点 \(m\) 边的带边权无向图。现在你要设计一条路线(可以重复经过点和边),要求要按顺序经过给定的 \(k\) 个点,且路线一定要在 MST 上。经过一个点时时间加上 \(t0\)(起点终点不算),经过一条边时时间加上边权 \(w_i\),求满足要求的最短时间。
2. 赛时
时间不够了……
Lca 板题,建个最小生成树直接查就行了。很抽象的题目,不知道为什么要放 T4。
10.6
150。
T1
1. Statement
给定一条线段的两个端点和一个半径为 \(r\) 的圆和它的圆心,保证线段和圆不相交。分别求出线段上任意一点到圆上任意一点的最小距离的最大距离。
2. 赛时
光是理解题目就花了 20min。先考虑 \(r=0\) 的情况,就是求出线段到点的距离。有很多种求法,赛时真的有点懵了,尝试了一下计算几何发现忘得差不多了。函数法也不好求,最后有点急了,只好写了个三分莽过去。
3. 赛后
其实真的有很多种方法求。考虑 \(r \not= 0\) 的情况,实际上最短距离就是到圆心的距离减去 \(r\)(显然),而最长距离就是到圆心的最长距离加上 \(r\)。
T2
1. Statement
有 \(m\) 个红绿灯,每个红绿灯只有在 \(a_i\) 的若干倍时刻才会亮绿灯。从一个红绿灯到下一个红绿灯的时间不计。求出从时刻 \(1 \sim n\) 出发的到达终点的时间。
2. 赛时
各种子问题全部写完用不了多久,有 70pt。看到随机数据决定觉得时间复杂度有点玄学。发现可以维护一个把若干个点合并成区间,但是怕过不了,一直在想没那么玄学的思路,反而浪费了思考下面几道题的机会。
3. 赛后
还有一个优化:当操作的数是 \(\gcd_{i=1}^{n} a_i\) 的因数时,这次操作没有意义。加上之后基本就能过了。
T3
1. Statement
给定可重集 \(S\),定义 \(F_0(S) = [\sum_{x \in S} x = M]\) 以及 \(F_k(S) = \sum_{T \subseteq S} F_{k−1} (T)(k > 0)\)。给定 \(M\) 和 \(k\),求 \(F_k(S)\)。
2. 赛时
心态有点炸了,有点懵。发现是背包,且答案一定要快速求出与 \(k\) 有关的部分。但是看到式子推了好久推不出来。。。
3. 赛后
设 \(F_0(T) = 1\),则它对答案的贡献为 \(k^{|S| - |T|}\)。然后 60pt 暴力背包就出来了。发现可以把长度这一维优化掉,可以通过逆元来转移,也可以重新设计状态直接变成 \(f_{i,j} = k \times f_{i-1,j} + f_{i-1, j-a_i}\)。
T4
1. Statement
给定长度为 \(n\) 的双元组 \(a\),\(a_i\) 包含种类和稳定程度。定义选出 \(k\) 种不同种类的 \(a_i\) 的价值为将这些双元组的稳定程度排序后最小的相邻两项的稳定程度之差。求出最大的价值。
2. 赛时
二分答案 + 检验。额,然后就卡在这里不知道怎么做了,由于种类数量太大,不可以状压。
3. 赛后
其实最近经常遇到这类的题,就是值的值域特别大不好维护,或者数据范围特别大,不好做。这就可以用随机化这种技巧。就像这道题,可以把每个 \(a\) 的颜色赋值成 \(1\sim k\) 中的随机数,跑一遍状压,发现答案只会更劣,且取到最优答案的概率大约在 \(3\%\) 左右,因此跑 \(200\) 遍取 \(\max\) 就行了。
但是题目还没有结束。这时候发现时间复杂度会直接爆炸。第一种做法是对 \(n\) 进行分段处理,\(n\) 越小,跑二分的次数就越大。第二种做法是对状压状态再进行状压,因为 \(2 ^ k\) 最大只有 \(32\),因此可以用 unsigned int 存,转移优化成 \(\operatorname{O}(1)\)。
心声
从开始集训到今天,每一场比赛都脱离了我的掌控。比赛结果也不尽人意。
我赛时思维真的很混乱,想题的时间反而比做题的时间长,而且写一道题正确率很低,要么要调很久,要么赛后要挂分。现在真的是到低谷了,思维跟不上,算法也不怎么会,心态爆炸,做题能力不行。就算我赛后听懂了题目的做法,但是我还是不能保证我在第二天的比赛时能调整状态做出来同样类型的题。
我想要提升自己的能力,但是我不知道从哪里开始补起。时间很紧张,三周不到的时间就要复赛了,还要赶文化课,呵。。。
迷茫
10.7
40 + 0 + 55 + 0 = 95
T1
1. Statement
有一些三元组 \((a,b,c)\),满足 \(a \in [1, A], b \in [1, B], c \in [1, C]\),定义一个三元组小于等于另一个三元组当且仅当第一个三元组的每个元素都小于等于第二个三元组的对应元素。有 \(n\) 次操作,每次操作给定一个三元组,把所有小于等于给定三元组的三元组全部删掉。求 \(n\) 此操作一共删掉多少三元组。
2. 赛时
看到题目心态爆炸,没有一点正解的思路。看了一会只发现数据一定满足给定三元组一定是 \((A, ?, ?)\) 或者 \((?, B, ?)\) 或者 \((?, ?, C)\)。然后思考了很久容斥,都没有思路,只能开后面的题。
回过头来看题,发现二维的情况非常好处理,单调栈可以直接解决。打满了暴力之后才发现三元组可以联想到坐标轴上的 \(x,y,z\)。但是这时已经有点急了,推不出来正解。
3. 赛后
其实可以枚举切面。假设枚举的是 \(z\) 轴上的切面,发现对于 \(C\) 固定的三元组就转换成了二维的问题。处理完是一个类似于阶梯的形状。对于 \(A\) 固定的三元组从侧面看也是一个阶梯,转换到切面就变成了把所有 \(y \le val\) 的位置切掉,这里 \(val\) 指对应的侧面的高度。同理,\(B\) 固定的就变成了把所有 \(x \le val\) 的位置切掉。发现 \(x,y\) 这两根线具有单调性,可以用双指针维护。
T2
1. Statement
\(n\) 个物品要经过 \(n-1\) 道工序。对于每个工序来说,如果此处只剩下一个物品,就必定将它排除。否则按照编号从小到大的概率考虑,对于每个物品有 \(p_i\) 的概率将它排除,然后把剩下所有物品全部传给下一道工序;有 \(1 - p_i\) 的概率把它留给下一道工序。显然,最后只会留下一个物品,求出最后一个物品的编号的期望。
2. 赛时
时间不太够了,60pt 的状压期望 DP 没时间写了。
3. 赛后
期望 DP 有一个显然的优化技巧就是分类分组,合并具有相同性质的状态。这道题就类似,可以枚举最后的编号,然后算出它的概率。DP 的时候所有的物品就分成了三组:编号小于它的物品,它自己,编号大于它的物品。设 \(f_{i,j}\) 表示考虑了前 \(i\) 个物品,当前枚举物品的排名为 \(j\) 的概率。
T3
1. Statement
给定长度为 \(n\) 的数组 \(a\) 和 \(b\),找到最大的正整数 \(k\),满足序列中存在长度为 \(k\) 的子段,使得这个子段中出现的所有数的出现次数 \(\ge b_k\)。
2. 赛时
信息太多啦,脑子有点乱。首先观察到 \(b\) 单调递减,尝试二分发现不可做。尝试枚举 \(l,r\) 然后优化,想了挺久发现依然不可做。尝试枚举 \(k\) 然后检验,依然不可做。观察 \(b\) 的单调性以为可以优化时间,避免不必要的枚举,想了挺久依然没有思路,打了暴力会过去做 A。
3. 赛后
首先观察到一个性质:对于一个任意不成立的子段,这个子段的子段也一定不成立。这个性质的本质是:如果在一个子段内一个数的出现次数小于 \(b_k\),那么对于这个子段的子段来说,它的 \(b\) 只可能越来越大,就更不可能合法,这其实就是 \(b\) 单调性引出的性质。根据这个性质,很自然的就会想到分治做法,但是单纯分治的时间复杂度是 \(\operatorname{O}(n \sqrt{n})\) 的,因此需要优化。
显然这个分治的瓶颈的一个重要因素就是分成了太多的区间,发现只要找到任意一个不合法位置的把区间分成两部分就行了,发现并不能做到每次都把区间分成均匀的两部分,因此要换一种思路去优化。
考虑启发式合并,只要每次分治的时间复杂度都为 \(\operatorname{O}(\min(mid-l,r-mid))\),时间复杂度就是对的。显然可以实现,只需要找到最短的一个段,然后把它分成两部分分治就行了。
但是最短的一个段不一定在一侧,所以需要用双指针(Meet in middle)的思想来做。
还没有结束。在分治的过程中还需要维护 \(cnt\) 数组,记录每个数的出现次数。只需要先把小区间的数删掉,然后分治大区间,再把小区间的数加上,分治小区间就行了。注意在无法分的区间还需要把这一段的 \(cnt\) 清空。
T4
1. Statement
给定长度为 \(n\) 的数组 \(b\),满足 \(\forall i \in [1,n], b_i \in [0, m]\),若 \(b_i = 0\),则表示 \(b_i\) 的值在 \([1,m]\) 中均匀随机。定义 \(f(l,r)\) 表示 \(b_l \sim b_r\) 这一段区间中的所有极长相等子段长度的平方和。
现在有 \(q\) 次操作,每次操作要么把 \(b_x\) 修改成 \(y\),要么查询 \(f(l,r)\) 的值。
2. 赛时
单点修改区间查询,是线段树没错了,但是不知道怎么维护。
3. 赛后
期望这类题目还有一种解法,就是转换成本质相同的问题。这道题可以转换成满足 \(b_i = b_{i+1} = b_{i + 2} = \dots = b_j\) 的 \((i,j)\) 数量。这个东西很容易就可以用线段树维护。先鸽着,等写出来再更新。
服了,写了一天,重构了 3 次代码,还是调不出来。。。
复盘
心态太不稳定了,遇到一道题不会要调整心态,合理分配时间,把易拿分的都拿了。最后再花时间思考正解。
10.9
T1
1. Statement
有一个 \(n\times m\) 的矩阵 \(a\),矩阵的每个元素是 \(1,2,3\)。可以任意交换两行,问是否经过若干次
交换,使得每一列都是单调不减的。
2. 赛时
遇到构造题太不自信了。
直接推就行了,显然对于每一种不合法情况来说,都存在一组 \(i,j\),是的对应的两列相互矛盾。这显然是充要条件,但我以为 T1 不可能这么简单就以为假了,想了好久其他做法。直接模拟就行了。
T2
1. Statement
有一个 \(n\) 层的塔,从上往下数的第 \(i\) 层有 \(i\) 个砖块,由于塔太高了,我们只能看得到最后一层,也就是第 \(n\) 层的砖块。
除了最后一层的砖块外,每一个砖块都和下面一层的两个砖块相邻,呈现这样的形状:
塔上面只有红黄蓝三种颜色的砖块,并且有以下规律:
- 若相邻的两块砖块是相同颜色,那么这两块方砖紧挨的上面的砖块也将会是相同的颜色
- 若相邻的两块砖块是不同颜色,那么这两块方砖紧挨的上面的砖块将会是没有出现的第三种颜色
现在告诉你最下面一层的 \(n\) 个砖块颜色(红黄蓝分别用 A B C 表示),需要你推出塔顶部的颜色。爬到塔顶的牛牛已经看到了顶部砖块颜色,并且偷偷告诉了你,作为本题的提示——它说它看到的是灰色(因为牛牛是色盲)。既然你已经有了提示,我相信你一定能做出这道题。
2. 赛时
遇到好几道这种合并的题了。
首先推了一下性质,发现不好推,就打了暴力。中途想过转过数字去处理,但觉得没用,就没有考虑了。之后考虑了很久其他带 \(log\) 的做法,都不好做,又推了很久特殊性质二,依然没有思路,最后还是推了好久性质,结果全假了。。。已经思考了 1h 一点进展都没有,就完全放弃了,开后面的题去了。
3. 赛后
这道题可以转成 012 来做。转成 012 之后性质就非常明显了:设底下的数分别为 \(x_i, x_j\),则顶上的数为 \(-(x_i + x_j)\),这就是杨辉三角,然后就秒了。
这种题可以算作一种专门的题型了,很多都是杨辉三角,如果没有显然的性质就要转换成杨辉三角。
T3
1. Statement
白浅妹妹前一段时间学习了 LIS(最长上升子序列)算法。
她随便生成了一个数组,这个数组长度是 \(n\),每个元素是一个 \([1,m]\) 之间的正整数。
然后她开开心心的求出了这个数组的 LIS 数组,其中,第 \(i\) 个元素代表以原数组第 \(i\) 个数结尾的最长上升子序列的长度是多少。
然而她把原数组弄丢了,请你帮她算算,原数组有多少种不同的可能。
2. 赛时
肯定是 DP。
这道题一开始信息太多了,脑子有点乱。
整理了之后发现有一个充要性质是所有合法 \(a\) 必须具有的: 按照 LIS 从小到大处理,对于同一个 LIS 的 \(a_i\),一定是随着 \(i\) 的上升单调不增的,对于比它小的 LIS,一定是大于这个位置的前缀最小值。
这个问题已经非常简单了,但是不知道怎么 DP。
3. 赛后
这类题目可以转换成 DP + 组合数学。这道题 \(a_i\) 最多只有 \(20\) 种不同的取值,可以从这里入手。设 \(f_{S,i}\) 表示选择状态为 \(S\),选了前 \(i\) 种数的方案数,转移很好转移。答案就是 \(\sum_{i=1}^n f_{2 ^ n-1,i} \times {m \choose i}\)
考虑优化:把填数的过程拆开,省去检验的过程和枚举子集的过程。设 \(f_{i,j,S}\) 表示考虑了前 \(i\) 种数,从后往前考虑到了第 \(j\) 位数,选数情况为 \(S\) 的方案数。从后往前是为了方便检验和转移,\(S\) 最后枚举是为了方便滚动数组。如果单纯的转移,求出来的答案是用了至多 \(i\) 个数凑出来 \(S\) 的方案数,只需要在统计答案的时候容斥一下就行了。
T4
1. Statement
敌方军团有 \(n\) 个军事基地等距离围成一个圆,编号为 \(1\sim n\),第 \(i\) 个和第 \(i+1\) 个相连(\(1 \le i < n\))。每个军事基地有一个战斗力 \(a_i\),当战斗力被削弱为 \(0\) 时即为消灭。敌方会在一些基地之间修建桥梁,联通两个军事基地变成.新的一个,值得注意的是如果两个桥梁相交叉则它们互相连通,即两个桥梁连接的军事基地也互相连通。一些联通的军事基地的战斗力是他们的和。
我方有一些轰炸机,轰炸能力为 \(k_i\),轰炸范围为 \(b_i\) 的轰炸机可以轰炸 \(b_i\) 个不同的未被消灭的军事基地 。每次轰炸会使被轰炸的军事基地减少 \(k_i\) 的战斗力。若轰炸中途某个军事基地已经被消灭则停止轰炸该军基地。定义完美轰炸指轰炸机轰炸的 \(b_i\) 个军事基地均没有中途停止轰炸(恰好炸完不算中途停止)。
指挥官会告诉你敌方修建了哪个桥梁,以及询问一台给定 \(k_i\) 和 \(b_i\) 的轰炸机是否可以完美轰炸 \(c_i\) 次。
每次询问独立,即轰炸并不造成实际影响。
2. 赛时
暴力写挂了,打到后面真的是急了。。。正解先留着,自习的时候写。
复盘
题目练少了,一些常见的套路都不知道。在卡题的时候直接开下一题。先打满暴力再做其他题。
10.10
100 + 30 + 50 + 0 = 180
T1
1. Statement
长度为 \(n\) 的价格列表 \(a\),每次操作可以花对应的钱买对应的物品,或者把所有的物品的编号循环加一。求进行了若干次操作后集齐所有种类物品的最小花费。
2. 赛时
节奏有点乱了,想复杂了。
看到题没有思路,完全没有往正解的方向想。选择开下一题。回到这一题,还是没有思路。勉强推出了一个假的性质,不好实现也不好写。这时候的思路和正解很像,但是就是不对。大概就是三分最大的段数,然后 DP / 贪心。其实硬做也是能做出来的,但是我太菜了,调了好久都没调出来。
3. 赛后
感觉我的思维方式有点问题,简单的问题总是容易想复杂,总是想不到一些显而易见的性质。
这道题如果直接枚举旋转次数,就直接秒了。题目真正复杂的地方是如果直接维护整体的局面根本不好做,但是如果对于每一个位置都反别考虑,就非常可做。在确定了旋转次数之后(设它是 \(l\)),则每个位置 \(i\) 的最小价格就是 \(\min_{j = i - l} ^ {i} a_j\),直接就是单调队列板题。
显然的,这个价值是一个单峰函数,因此可以三分。
T2
1. Statement
给定一个序列 \(a\),求最小值或最大值都不在区间首尾的子段数量。
2. 赛时
非常好做的一道题,20 min 直接切了,信心大增。
直接硬做,考虑从后往前分别维护一个上升和下降的单调栈,假设 \(i\) 为区间的左端点,则 \(j\) 一定大于等于两个单调栈栈顶位置的最大值。这时候会发现,单调栈内所有的元素作为右端点都是不合法的,直接维护单调修改,区间查询的数据结构就行了。
3. 赛后
也可以容斥,最不好做的部分就是首尾分别为最大值和最小值的情况。分别维护一个上升和下降的单调栈二分就行了。
T3
1. Statement
定义一种构造字符串的方式为在已有字符串的没两个字符之间插入一个字符 \(c\)。给定一个长度为 \(n\) 的 \(c\) 序列,初始时 \(s\) 为空串,接下来按顺序对于每个 \(c_i\) 执行一次构造。求最终构造完成之后的本质不同的字符串数量。
2. 赛时
打了个 50pt 的暴力就继续去磕 A 了。
3. 赛后
其实正解也不难想,数据范围提示的已经很明显了。
显然,最终的字符串长度是 \(2 ^ n\) 级别的,只有 \(\log\) 的算法才能做。看到 DP 还有 \(\log\),那基本只能是矩乘了。刚好,本质不同子序列有一种方法也可以矩乘。设 \(f_{i,j}\) 表示前 \(i\) 个字符中以字符 \(j\) 结尾的本质不同的子序列的数量。
直接把 \(f\) 的每一位的 \(26\) 个元素拿出来做个矩阵就可以了。
但是还需要明白题目的构造方法。设 \(T_i\) 表示经过了 \(i \sim n\) 个步骤之后的字符串,则 \(T_i = T_{i-1} + c_i + T_{i-1}\),这显然就是分治,然后这道题就结束了。
T4
1. Statement
给定一个 \(n\) 点 \(m\) 边的无向图,你可以删掉任意 \(k(k \in [1,2])\) 条边,求有多少种删边方案使得删过之后的图不连通。
2. 赛时
没有时间写,全在磕 T1。
3. 赛后
\(k=1\) 的情况就等同于求割边。
\(k=2\) 的情况分为以下几种:
- 两条非树边,无意义。
- 一条树边,一条非树边,可以选一个桥,任意非树边;或者一条树边和唯一的可以替换它的非树边。
- 两条树边,两个桥;或者两个都不是桥,只要两条边的替换边边集一样就可以删。
下面考虑如何证明:满足该条件的两个点中间一定是一个独立的连通块,是的删掉这两条边之后中间的连通块和剩余部分断开了。
复盘
题做少了,感觉要多做一些思维题,改变一下思维方式,考试的时候不要想太复杂。整体来说其他题的节奏还可以,但是 T1 耽误了太多时间。
10.13
上去溜去补文化课了,没有考。
T1
1. Statement
给定 \(n\) 点完全图,第 \(i\) 个点上写有数字 \(A\)。边 \((i, j)\) 的权值为 \(|A_i - A_j|\)。
从图中选出 \(2 \times m\) 个点和 \(m\) 条边,每一条选中的边恰好连结两个选中的点,每一个选中的点恰好被一条选中的边连结。一种匹配的权值定义为所有选中的边的边权和。输出所有匹配中最小的权值。
2. 赛后
3min 出解。首先问题可以转化成选 \(m\) 对数,是的每组的差之和最小。先排序,发现任意一种选择方案只要交叉就不是最优的。直接 \(n ^ 2\) DP 就行了。
这道题还可以更快,反悔贪心就直接秒了,不过只是口胡了一下,不知道好不好实现。
T2
1. Statement
给定长度 \(n\) 的正整数序列,其中有些位置为空,另一些位置则已经填好了数字。你需要删掉序列中的任意一个位置,然后在剩余的位置中填入数字使得其依然为 \([1, n]\) 的排列,输出操作字典序最小的排列。
2. 赛后
一道比较简单的构造,分类讨论就行了。显然,对于空位从小到大插没出现过的值一定是最优的。对于两个非零来说,如果 \(a_i > a_{i+1}\) 就直接删去 \(a_i\)。如果 \(a_i \not = 0\) 且 \(a_{i+1} = 0\),则若 \(a_i >\) 未填数中最小的数,则删去 \(a_i\)。如果 \(a_i = 0\),如果后面最小的非零数小于未填最小数,则删去后面最小的非零数,移到这一位。
T3
1. Statement
斯坦纳树是这么一类问题:给定一张图 \(G = <V, E>\),和点集 \(V_1\),你需要找到原图的一张子图(即原图中删去一些点和边之后得到的图),令子图为 \(G' = <V', E'>\),满足 \(V_1 \subseteq V'\) ,子图 \(G'\) 连通,且子图中的边权和尽量小。
现在给定一棵树 \(G\)(树也是一种特殊的图,对应上文的图 \(G\)),每次给出一个点集 \(V_1\),求这个点集在树 \(G\) 上的斯坦纳树的边权和。
请你输出希望你对每个 \(i (1 \le i \le n)\),验证对上面题目解法在点集 \(V_i = \set {P_1, P_2, \cdots, P_i}\) 上的正确性,\(P\) 为 \(1 \sim n\) 的排列:
- 建一个新的完全图 \(G'\),图中每个点都对应着询问点集 \(V_1\) 中的一个点,两个点之间的边权为其在 \(V_1\) 对应的点的树上距离。答案为此完全图的最小生成树大小。
2. 赛后
思维有点混乱。直接求最小生成树,一定会有一条边被 \(2\) 次选中。考虑到关键点是分开来的,因此建棵虚树,设树上不在不是关键点的点为虚点,发现只要有一个虚点有 \(3\) 个及以上的分叉,就一定有边会重复统计。
当有虚点分叉数小于3时:
1.分叉数 \(= 2\),直接把虚点两端的连起来,不用再管虚点了。
2.分叉数 \(= 1\),直接删去虚点(此时它一定是叶子,不会对答案造成任何影响)。
当边权为 \(0\) 时,把所有点加入一个连通块中,只有连通块为空,这整个连通块才能删除。
加点不好做,考虑删点。当不存在虚点时,做法正确。
T4
1. Statement
给定 \(n, k, p\),求出 \(n\) 个点的无标号无根树中,直径长度为 \(k\) 且恰有 \(p\) 条直径的树的数量 \(\bmod 998244353\) 的结果。
2. 赛后
超级大 DP,留着练 DP 的时候写。
10.14
100 + 100 + 100 + 0 = 300
本来以为大家都会 AK 的。。。
哎,任重而道远啊。。。还有很多事情要做。
T1
1. Statement
给定长度为 \(n\) 的字符串 \(s\),\(m\) 个字符串 \(t\),对于 \(s\) 中的任意一个 *,可以把它替换成任意一个字符串。对于 \(s\) 中的任意一个子串,求它变成 \(t\) 的任意一个字符串的方案数之和。
2. 赛时
考虑换一种视角去看,问题就变成了对于每个字符串 \(t_i\),求 \(s\) 中有多少个子串使得它可以变成 \(t_i\)(个人认为这是一个很经典的转换吧)。然后直接硬核 DP 就行了,一开始以为要优化,但发现 \(\operatorname{O}(n \sum{|t_i|})\) 可以直接过,就写了。
思考时间 5min,写题加调题大概在 50min 之内。节奏掌握比较好。
T2
1. Statement
给定一棵 \(n\) 点的树,每个点有两种颜色,每条边有边权,定义 \(\operatorname{dis}(i,j)\) 表示 \(i\) 到 \(j\) 的简单路径上的最大值,黑点的集合为 \(S\),白点的集合为 \(T\),定义树的价值为 \(\sum_{u \in S} \sum_{v \in T} \operatorname{dis}(i, j)\)。现在至多可以改变一个颜色,最大化价值。
2. 赛时
到现在还是想不明白为什么这道题会出现在提高组里面,大概是出题人想到了一个很好的并查集题目但是忽略了这道题 \(n^2\) 可以直接暴力吧。。。看到数据范围我整个人都不自信了,一开始以为是什么换根,LCA,启发式合并,并查集。。。但是发现 \(n \le 3000\),直接震惊到我了,打了个 Dfs 直接开下一题了。
3. 赛后
看了下题解发现可以并查集做。其实还有一种方向就是拆贡献。从边的方向考虑,把边从小到大排序,就变成了一个经典问题。
T3
1. Statement
初始时有一根长度为 \(x\) 的木棍,接下来可以变出三个长度严格递增且长度位于满足 \(x < l < 4 \times x\),求有多少种变木棍方案使得这四根木棍中存在三根可以组成三角形。
2. 赛时
看到存在就想到容斥。变成总方案数减去不合法方案数。现在一开始的总方案数就不好求,手推了一下发现就是 \(3n \choose 3\)。然后就是不合法方案数,设剩下三根为 \(a,b,c\),则要满足 \(x < a \le 4x - 2, b \ge a + x, c \ge a + b\)。这个东西很容易表示出来,其实就是由类似于 \(S = \color{blue}{1} + \color{red}{1 + 2} + \color{green}{1 + 2 + 3} + ...\) 这样的公式转换而来的。
接下来就只剩硬核推式子了。我记得这个通项公式很简单,但我忘记了 \(\texttt{QWQ}\),朦胧中记得好想要除以 \(6\)。然后就开始找规律了,但是好像还是没有什么规律。这时候联想到算总方案数的组合数好像系数就是 \(\frac{1}{6}\)!然后就把这个东西转换成组合意义发现刚好可以对的上,计算了一遍发现通项公式就是 \(n(n+1)(n+2)\)。
当 \(x\) 是偶数时,需要求的东西是 \(1 + 1 + 2 + 3 + 1 + 2 + 3 + 4 + 5 + ...\)。发现差别不大,这个和可以通过解方程由刚才求得的东西求出来。当 \(x\) 是奇数的时候也是类似的。然后这道题就结束了。
3. 赛后
题解的方法非常值得借鉴。我赛时的推式子需要耗费大量的时间。题解是非常稳定的。只需要用数学归纳法掌握出每一项的递推式,然后硬核矩乘就行了。
T4
1. Statement
有 \(n\) 种文明,编号为 \(i\) 的文明初始时排名为 \(i\),有 \(k\) 个世纪,每个世纪会发生 \(a_i\) 场战争,每次战争会随机把一对不同的文明排名交换。你可以选择在一个世纪初选择一个别人没选过的专属文明,如果你在这个世纪没有选择任何文明,则会有一个人选走排名第一的文明。求出对于每个世纪 \(i\),在这个世纪初选择文明最终的期望最小排名。
2. 赛时
思路有点混乱,期望 DP 好像不适合我。。。最终暴力都没有打出来。
3. 赛后
题解没看懂,选择有时间再专门练期望 DP。
10.15
100 + 90 + 10 + 0 = 200,原地爆炸。。。
T1
1. Statement
给定 \(n\) 个双元组,代表每个人得分。每个人每题得分有 \(\frac{1}{2}\) 的概率 Fst,变成 0 分。求出每个人的期望排名。
2. 赛时
一眼题,用一个桶维护后缀期望人数就结束了。但是赛时有点不自信,又想了一会正确性,耽误了部分时间。
T2
1. Statement
初始时你在点 \(1\),当你在点 \(x\) 时,可以跳到点 \(2x\);当 \(x \equiv 1 \pmod 3\) 时,可以跳到 \(\frac{x-1}{3}\);当 \(\min{(|x|, |x - d|)} \le l\) 时,可以跳到点 \(x - d\)。现在给定 \(q\) 个点,对于每一个点来说,都要构造出一组能够跳到这个点的长度 \(\le 1500\) 的跳跃方案。
2. 赛时
看到题目的那一刻,噩梦开始了。显示花一部分时间理解了题意,感觉是个 CF 类型的题目,然后就开始各种联想推性质。一开始就发现了可以倒着推,但是对于 1500 的限制有点不自信,以为要通过每种神秘性质跑 Bfs,然后就开始了调同余最短路的折磨。中途发现了各种性质,比如它的操作次数一般都特别小,因此正数时可以直接乱搞。但是赛时不是很自信,不敢负数时直接乱搞。最后调了 2h 比赛都快结束了发现唐了直接乱搞缩小范围然后一直加 d 变成正数这道题就结束了。哎……
T3
1. Statement
\(n + 1\) 个点的树,每个点的编号为 \(0 \sim n\)。点 \(i\) 可以访问集合 \(S_i = [\max\{1, i - k\}, i) \cup \{0\}\) 中的点。对于每个点 \(u\),求 \(\sum_{v \in S_u} \operatorname{dis}(u,v)^2\)。
2. 赛时
什么神秘题目啊啊啊。赛时就那么点时间,谁会想到有一道大码量数据结构题啊。这道题就硬拆贡献硬做就行了,我赛时拆出了 \(6\) 项,直接懵了,以为还有什么性质可以简化。。。然后就一直没做出来。
3. 赛后
以后再也不敢写错数据结构题了,绷不住了,这道题目花了我一天的自习时间才调出来。其实这道题目没什么思维含量,就是用树剖 + 线段树硬维护这 \(6\) 项。我还临时学了个树剖,哎。。。不过有一个 \(little \ trick\),就是项中的 \(lca\) 可以通过链修改链查询来做,本质上就是把两个点的贡献转换成了一个点修改,一个点查询。然后这道题就没了。
T4
1. Statement
为了认识更多的异性朋友,牛牛在各类活动中做志愿者(牛牛是女的?)。这天,牛牛在大型赛事 \(\text{AUPC (Asia University Program Competition)}\) 中担任志愿者,他的任务是在大厅门口接待选手们。
接待的过程是漫长而枯燥的,牛牛把这一过程中自己的心情变化用一个整数来描述,他称这个整数为他的开心度。大厅中有一个休息用的沙发,沙发到门口的距离为 \(L\) 米。牛牛可以在门口到沙发间直线往返,他用四个参数 \(x_{0, 0}, x_{0, 1}, x_{1, 0}, x_{1, 1}\) 来描述他在门口,从门口向沙发走,从沙发向门口走和在沙发时的开心度变化。具体来说:
- 当牛牛站在门口时(即牛牛与门口的距离为 \(0\) 时),牛牛的开心度每秒减少 \(x_{0, 0}\);
- 当牛牛从门口向沙发走去的时候,牛牛的开心度每秒减少 \(x_{0, 1}\);
- 当牛牛从沙发向门口走去的时候,牛牛的开心度每秒减少 \(x_{1, 0}\);
- 当牛牛躺在沙发上摸鱼的时候(即牛牛与沙发的距离为 \(0\) 时),牛牛的开心度每秒增加 \(x_{1, 1}\)。
牛牛的移动速度固定是 \(1 \operatorname{m / s}\)。牛牛只有站在门口(即牛牛与门口的距离为 \(0\) 时)才能接待选手,且因为牛牛手速惊人,接待选手可以看作是瞬间完成的。
为了能够快乐地摸鱼,牛牛事先收集了一些信息:
- 一共有 \(n\) 名选手需要接待;
- 第 \(i (1 \le i \le n)\) 名选手会在时刻 \(t_i\) 到达大厅门口并等待接待,他的耐心值为 \(p_i\),友善值为 \(f_i\);
- 如果牛牛在时刻 \(T (t_i \le T \le t_i + p_i)\) 接待第 \(i\) 名选手,那么牛牛的开心度会瞬间上升 \(f_i \times (t_i + p_i − T)\),但是如果第 \(i\) 名选手在时间段 \([t_i, t_i + p_i]\) 都没有被牛牛接待,这名选手就会向主办方投诉,从而导致牛牛丢掉这份宝贵的志愿者工作。
- 接待完所有选手的那一刻,牛牛的工作就完成了。
在时刻 \(0\),牛牛站在门口(距离门口 \(0\) 米),开心度为 \(0\)。现在牛牛想知道,不被选手投诉的前提下,在工作完成的那个时刻,开心度最多可以是多少(可以是负数)。
2. 赛时
心态有点炸了,没有写。
3. 赛后
听说要用 Slope Trick,等到有时间了再写。
复盘
太不自信了,思考各种做法浪费了太久时间。面对很多性质,信息的题目时思维非常混乱,没有一点顺序。算法根本没有掌握,题目做太少啦,比赛阅历太少啦。这场比赛心态调节比较好,调了 2h T2 还没有放弃。除此之外,还应该掌握更多骗分的技巧。
10.16
T1
1. Statement
一个单词有 \(\texttt{N,A,V}\) 三种词性。一个短语 \(\texttt{NP}\) 由 \(\texttt{N | A + NP | NP + NP}\) 组成。一个句子 \(\texttt{S}\) 由 \(\texttt{NP + V + NP}\) 组成。现在给定一些单词和它的若干个词性,求是否能够合理排布这些单词的词性(同一个单词可以为多种词性)使得它们组成一个句子。
2. 赛时
显然,一个短语一定是由名词结尾的,且中间不能出现 \(\texttt{V}\),一个句子只能中间出现 \(\texttt{V}\),直接判就行了。
T2
1. Statement
实现一种数据结构:
- 往第 \(i\) 个容器顶端插入 \(x\) 个 \(y\)。
- 在第 \(i\) 个容器中从顶到底弹出 \(x\) 个元素,输出最后弹出的元素。
- 把第 \(i\) 个容器中的所有元素从顶到底依次插入第 \(x\) 个元素的顶端。
2. 赛时
一眼链表,当然这也是一道优秀的 FHQ / Splay 练习题。考虑如何翻转,如果你说打 lazy tag,那你就完了。lazy tag 需要考虑非常多的情况,非常不好写,导致我赛时调了 2h 都没调出来。不过也有我题练少了的原因。
3. 赛后
实际上根本不需要真正翻转。看来我学的双向链表一直都是假的。。。其实双向链表并不知道前面和后面,只需要我们记录出上一个出现的元素就可以按顺序遍历,这道题直接加边遍历就没了,哎。。。
T3
1. Statement
对于一个可重集 \(S\),定义 \(f(S) = \sum\limits_{T \subseteq S} [\operatorname{fib}(\sum\limits_{s \in T} s)] ^ 2\)。现在有一个数组 \(a\),有两种操作,操作 1 把 \(a_x\) 变成 \(y\),操作 2 计算 \(\sum\limits_{i = l} ^ r \sum\limits_{j = i} ^ r f(\{a_i, a_{i+1}, \dots, a_j\})\)。
2. 赛后
显然这个操作需要用线段树维护。目前来说这并不好合并。先考虑把平方推一下式子,最终推出来是 \(g(i) = 2 \times g(i-1) + 2 \times g(i-2) - g(i-3)\)。这只能矩乘来做。考虑集合怎么处理。每加一个数只能不变或者乘上一个矩阵。矩阵有分配律,因此可以把矩阵作为状态来做。然后这道题就没了,用线段树维护矩阵就行了。
T4
1. Statement
定义偶数为数字前一半和后一半完全一致的数。初始时给定一个偶数,每次会添加最少的数字在偶数末尾使得它形成新的偶数,直到它的位数超过 \(n\)。现在 \(q\) 次询问,求偶数第 \(l\) 到 \(r\) 位组成的整数。
2. 赛后
字符串分治好题,等到有时间了再写。
10.20
T1
1. Statement
\(n\) 对球,每对球都是不同的颜色,每次随机取出 \(2\) 个球,当球颜色相同时就会开心一次。求开心的期望次数。
2. 赛后
稍微推一下式子就行了,对对球分开考虑,最终答案就是 \(\frac{n}{2n - 1}\)。
T2
1. Statement
一个长度为 \(m\) 的环上有 \(n\) 个区间,每个区间有一个起始点和长度,对于第 \(i\) 个区间让它的起始点移动到 \(j\) 需要代价 \(c_{i,j}\)。现在要在环上找到一段连续的长度为 \(k\) 的区间,使得它不被这 \(n\) 个区间中任意区间覆盖,你可以安排这些区间,求最少的代价。
2. 赛后
一眼题,直接 RMQ 就秒了,但是 \(10^7\) 带 \(\log\) 有点紧,又由于它的区间长度是固定的,直接单调队列就行了。
T3
1. Statement
纽约可以简化成 \(n\) 点 \(m\) 边的无向图,每条边直接坐车需要的代价是 \(\lceil \frac{w}{r} \rceil\),多条边可以连在一起坐车。有 \(k\) 路公交车,做了公交车则只需要付 \(c_i\) 就可以在它的任意站点之间往返。\(q\) 次询问,每次询问 \(x\) 到 \(y\) 的最小花费。
2. 赛后
显然边越多连在一起做车越划算,直接记录余数和分母跑最短路就行了。考虑公交车如何处理,只需要利用类似于线段树优化简图的方法,把所有站点都连在一个点,上车不需要钱,下车需要钱就行了。
T4
1. Statement
求一个序列的极长子序列的个数。
2. 赛后
显然需要 DP。对于一个极长子序列来说,第一个元素一定是最小的,最后一个元素一定是最大的。假设要从 \(i\) 转移到 \(j\),则 \(\forall i < k < j\) 来说,\(a_k\) 一定不在 \(a_i\) 和 \(a_j\) 中间。很自然的就会想到用数据结构维护 DP。发现收集状态这一部分并不好做,考虑怎么在更新的时候的维护更多信息。对于能够从 \(i\) 转移到 \(j\) 的情况来说,一定满足 \(i \sim j\) 所有大于 \(v_i\) 的值的最小值大于等于 \(v_j\)。只需要转移的时候更新一下把所有小于 \(v_i\) 的部分更新一下 \(mn\),查询的时候只需要求满足条件的和就行了。
区间取 \(\min\) 直接吉司机或者 Treap 就行了。
10.21
T1
1. Statement
给定两个 01 串 \(A,B\)。\(q\) 次询问,每次询问 \(A_{l1 \sim r1}\) 和 \(B_{l2 \sim r2}\) 中不同的数 \(\operatorname{mod} 2\) 的值。
2. 赛时
一眼题,直接前缀异或就秒了。
T2
1. Statement
在左下角是 \((0, 0)\),右上角是 \((W, H)\) 的网格上,有 \((W + 1) \times (H + 1)\) 个格点。
现在要在格点上找 \(N\) 个不同的点,使得这些点在一条直线上。并且在这条直线上,相邻点之间的距离不小于 \(D\)。求方案数 \(\bmod 10 ^ 9 + 7\)。
2. 赛时
寄了,想了一会发现可以枚举起始点和终点组合数学硬算,细节有点多,选择先开下一题,然后噩梦就开始了。
3. 赛后
先回到这道题上面,发现相同的长度的方案数是一样的,只需要枚举长度再乘一个数就行了。决策失误,应该先开这一题。
T3
1. Statement
牛牛有一棵 \(n\) 个点的有根树,根为 \(1\)。
我们称一个长度为 \(m\) 的序列 \(a\) 是好的,当且仅当:
- \(\forall i \in (1, m]\),\(a_i\) 为 \(a_{i − 1}\) 的祖先或 \(a_{i − 1}\) 是 \(a_i\) 的祖先;
- \(\forall 1 \le i < j \le m, a_i \neq a_j\)。
你需要帮助牛牛求出最长的序列长度。
2. 赛时
先莽了 2 次贪心发现都假了,开始认真想。显然的,最优的方案一定是从底到顶走。每一个节点可以有两种选择,分别是选择两个子树内的值和一个子树内的值和一个它放弃的值。思路很明确了,但是 Dsu on Tree + multiset 调了 1h 都没调出来,我太菜了。。。最后写了个堆暴力合并,时间复杂度是错的,赛时时间不够了,以为今天是简单场,用可并堆可能是想复杂了,所以就没写。
3. 赛后
真是可并堆啊。赛后赶紧练了一下左偏树和 Dsu on Tree。其实这道题不用这些技巧也是能做出来的,就是线段树硬做,二分找到最大次大值合并,但是是 \(\log^2\) 的,常数有点大。
T4
1. Statement
定义一个数的 se 序列为其一个数位和为 \(10\) 的子段。
定义一个数是 ll 数,当且仅当它的每一个数位都在至少一个 se 序列中。
现在牛牛想随机生成一个 \([0, 10 ^ n)\) 范围内的数送给牛妹。具体地,每一位上的数字为 \(i\) 的概率为 \(a_i\),且保证 \(\sum_{i = 0} ^ 9 a_i = 1\)。
现在牛牛想知道这个数为 ll 数的概率。
2. 赛时
最后 30min 期望 DP 部分分都打炸了,心态爆炸。
3. 赛后
好像是 bm,神奇多项式题目,留给卡老师贺吧。
10.23
信心赛就没什么参考意义了。
今天开题异常顺利,T2 见过类似的 Trick,直接秒了,T3 死磕了 3.5 h 才磕出来,T4 时间不够正解匆匆忙忙写挂了,优化也没加。漏洞还是太多了,要趁着接下来的几天赶紧恶补思维题和代码源比赛。
大家都发挥得很好,这次纯属运气好。还是没有达到预想的分数,还是做的不完美。。。
T1
1. Statement
定义 \(f(x)\) 表示 \(x\) 除 \(1\) 以外的所有因子的 \(\gcd\)。求 \(\sum\limits_{i = l}^{r} f(i)\)。
2. 赛时
看到题目就知道是信心场了。很显然啊,一个数如果有多个质因数,则 \(f(x)\) 一定为 \(1\),否则就是唯一的质因数。直接欧拉筛就秒了。
T2
1. Statement
给定 \(n\) 个数和 \(q\) 次询问,每次询问给定一个数 \(x\),求给定的 \(n\) 个数中有没有数 \(y\) 满足 \(y \And x = x\)。
2. 赛时
阳寿要没了。。。这不就是一模一样的 Trick 吗。见 代码源 day 5 T1,只不过原题甚至还需要跑遍 Bfs。然后直接秒了。
现在回忆一下这种做法的本质,其实就是类似于线段树优化建图这样的原理。对于一个状态图来说,如果只需要关心部分的转移,则只需要把图简化成类似于树的结构,这也有点像 kruskal 重构树,不过差的有点远了。本质上就是减少了冗余的转移。
T3
1. Statement
给定一个字符串 \(s\),\(s\) 可以无限拼接。现在 \(q\) 次询问,每次给定一个字符串 \(t\),\(t\) 中的 * 表示通配符。\(t\) 中出现的数字代表前一个字母连续出现了这个数字次。求最少的 \(s\) 的前缀使得它有一个子序列是 \(t\)。
2. 赛时
思路真的很简单,不知道为什么要扯到自动机上面。就是每次肯定选后面第一个是最优的。然后出现多次就找循环节就行了。细节有点多,调了 2.5h。中间心态差点爆炸。
T4
1. Statement
有 \(0 \sim n + 1\) 个点,每个点可以耗费 \(1\) 的时间转移到相邻的点,也可以在当前点停留 \(1\) 单位的时间。\(m\) 次信息,表示点 \(a\) 会在时刻 \(b \sim c\) 消失。初始时你在点 \(0\),求到点 \(n\) 的最小耗费时间。
2. 赛时
就 40min 对我来说真的不够。。。首先 \(n ^ 2\) DP 可以直接想出来。然后就想出来可以把它转化成许多个区间组成的图,然后就直接想出可以跑最短路。但是时间真的不够了,只有 20min 留给我实现了。最后 30s 终于调过了样例,极限!但是已经考虑转移时间复杂度是假的,可以用二分来优化,只不过没有时间实现了。交上去有 60pt,一部分是一些情况没有判到,另一部分是 TLE。
3. 赛后
根本没有必要写最短路。因为每次只可能转移到前后两个点。直接贪心走就行了,走不了就回去,这样做正确性显然。
10.24
「致敬传奇飞行员佐巴扬」
T1
1. Statement
\(n\) 个长方体,求至少被 \(n-1\) 个长方体覆盖的整点的数量。
2. 赛时
看到神奇几何题想起了不好的回忆,果断选择开 T2。开完 T2 回到 T1,发现可以容斥,但是当时唐了,没有发现直接前缀后缀求交就结束了。然后发现了另一个性质,对于每个轴来说满足条件的段只有三段,直接离散化然后模拟就结束了。
但是赛时没删调试,导致常数乘二,本开常数就很大了,再加上只有 500ms,被卡常卡到了 60pt。。。
T2
1. Statement
长度为 \(n\) 的序列 \(a\),\(q\) 次询问,每次给定区间 \([l,r]\),求区间中是否存在 3 个不同的数使得它们可以拼成三角形。
2. 赛时
第一眼以为是数据结构,想了一会考虑从反面考虑发现了一个性质:如果 \(a + b \le c\),则这个数是以指数增长的,这是一个非常经典的 Trick,说明当区间长度 \(>= 88\) 时,就必定存在解。对于 \(< 88\) 的区间来说,直接暴力排序判就结束了。
T3
1. Statement
长度为 \(n\) 的序列 \(a\),\(q\) 次操作,每次要么翻转一个左边界单调上升的固定长度的区间,要么求一个点的值。
2. 赛时
第一眼 FHQ,但是看到 500ms 选择放弃。注意到区间长度固定并且左边界单调上升,想到了滑动窗口,但是感觉和区间翻转差得有点远就没继续想了。最后推了很久性质还是什么都没推出来。
3. 赛后
滑动窗口是可以做的,只要再深入想一下这道题就没了。只需要用 deque 维护就行了。
T4
1. Statement
给定一张包含 \(n\) 个点的图,每个点的权值分别为 \(a_i\),对于任意点对 \((i, j)\),如果满足 \(a_i \And a_j = 0\),则它们之间有边。
初始时有一个空集合 \(S\),每次可以选择一个不在集合中的点 进行如下两种操作之一:
- 直接将 \(v\) 加入集合,代价为 \(0\)。
- 选择一个在集合中且与 \(v\) 有边相连的点 \(u\),将 \(v\) 加入集合,代价为 \(a_u\)。
求可以获得的最大代价总和。
2. 赛时
一开始想到了生成树,大样例也过了,没有仔细思考正确性,然后赛后挂惨了。
3. 赛后
因为没有考虑树的方向对答案的影响,所以直接这么做正确性堪忧。由于每次操作都会累加父亲的权值,而每个节点都有父亲,为了正确地累加权值,我们可以先将所有点的权值减去,并将任意两点之间边的权值设置成两点权值的总和。这样每个点在接入树的时候,它本身被减去的权值会被抵消,而父亲的权值会额外累加一次。

浙公网安备 33010602011771号