2024蓝桥杯省赛C/C++程序设计A组题目简析
2024蓝桥杯省赛C/C++程序设计A组题目简析
A
题意:计算一段区间内日期的中文表达的总笔画数>50的天数
按照题意枚举即可。注意个位数字前面需要加一个“零”,也就是多13笔。
B
题意:\(5\times5\)的棋盘下五子棋,最终下满棋盘并和棋的情况数
dfs或者遍历二进制去枚举棋子位置的情况均可。
假设做法是去枚举黑棋位置的所有情况,一个简单的验证对错的方法是把黑棋的数量分别设置为12/13运行一次,如果答案不等说明写错了。
C
题意:有 \(n\) 个士兵,第 \(i\) 个士兵至少需要训练 $ b_i$ 次,每次训练花费 \(a_i\)。可以每次花钱训练一个士兵,也可以花费 \(S\) 将所有士兵训练一次。求将所有士兵训练达标的最小代价。(\(n\leq 2\times10^5\))
比较明显的贪心算法。先将士兵按照 \(b_i\) 排序,也就是越后面的士兵需要的训练次数越多。从第一个士兵开始往后遍历,做到 \(x\) 时,如果 \(a_x+a_{x+1}+\dots+a_n >S\),那么打包训练更优,做 \(b_x-b_{x-1}\) 次打包训练(\(b_x-b_{x-1}\) 为总共需要次数减去已经执行过的打包训练数);否则,单独训练已经优于打包,直接让答案加上 \([x,n]\) 区间内每个士兵剩下需要单独训练的次数 \(\times\) 训练花费,并退出循环。复杂度 \(O(n\log n)\).
D
题意:有两棵大小分别为 \(n,m\) 的以 \(1\) 为根的树,每个节点有权值,分别为 \(a_i,b_i\)。起初两个人 \(A,B\) 分别站在两棵树的根节点,两人各自一路往下走直到叶子节点,设 \(A\) 经过的结点的权值按照顺序组成序列 \(a_{k_1},a_{k_2},a_{k3}...\),\(B\) 的序列为 \(b_{l_1},b_{l_2},b_{l_3}\dots\),求两个序列的最长公共前缀的可能最大值。(\(n,m\leq 2\times 10^5,\ a_i,b_i\leq 10^9\))
题目转化为:对于第一棵树上的每个节点 \(x\),能否在第二棵树上找到一条一样的从根节点向下的权值路径。
需要快速判断两个序列是否一样,使用哈希函数。先dfs第二棵树,在递归时记录当前节点到根节点 \(1\) 这一段的哈希值,设节点 \(x\) 到 \(1\) 这一段的哈希值为 \(p_x\)。
然后dfs第一棵树,记录当前节点的深度和哈希值,设节点 \(y\) 到 \(1\) 这一段哈希值为 \(q_y\),每次只需要看看集合 \(\{p_x\}\) 里是否有 \(q_y\),如果有,说明存在相同路径,答案与 \(y\) 的深度取 \(max\)。
复杂度 \(O(n\log n)\)
E
题意:给定一个序列 \(a_1,a_2\dots a_n\),求出最小的 \(x\),使得能够选出 \(a_1,a_2\dots a_x\) 中的 \(k\) 个,使得这 \(k\) 个数的方差小于 \(T\)。
\(n\leq 10^5,a_i\leq10^5,T\leq 10^9\)
\(x\) 的可行性单调(即 \(x\) 增长,成功的概率递增),可以二分 \(x\) 得出答案。问题转变成如何判定前 \(x\) 个数是否可行,即求出前 \(x\) 个数中选出 \(k\) 个的最小方差。
为了让方差最小,一定选取排序后相邻的 \(k\) 个数。所以有效的选法只有 \(x-k+1\) 种。将方差的式子拆分括号,变成 \(\sum_{i=1}^{k}x_i^2-\frac{\sum_{i=1}^k x_i}{k}\),得到独立的两个部分,于是只需分别记录 \(\sum_{i=1}^{k}x_i^2\) 和 \(\sum_{i=1}^kx_i\),当区间从 \([p,p+k-1]\) 变成 \([p+1,p+k]\) 时 \(O(1)\) 地修改两个值,就可以算出方差的最小值,进而判定是否可行。
复杂度 \(O(n\log^2n)\) 。可改用倍增避开每次判定的暴力排序优化为 \(O(n\log n)\)。
F
题意:给定一棵 \(n\) 个节点的树,树上的节点 \(x\) 的颜色为 \(c_x\)。有 \(q\) 次询问,每次给出两个节点 \(a,b\),问在 \(a,b\) 之间的树上路径上的节点有多少种不同的颜色。
\(n\leq 10^5,c_i\leq 20,q\leq 10^5\)
几乎是树链剖分的模板题。由于颜色的种类很少,只需对每种颜色 \(p\) 开一个数组统计 \(dfs\)序上的颜色为 \(p\) 的结点个数的前缀和,在剖出的每条树链上看看每种颜色有没有即可。
复杂度 \(O(20\ n\log n)\)
G
题意:给定序列 \(x_1,x_2,\dots x_n\),四元组 \((a,b,c,d)\) 是好的当且仅当 \(x_a\) 被 \(x_b\) 整除,\(x_c\) 被 \(x_d\) 整除且 \(a,b,c,d\) 互不相等。问有多少个好的四元组。
\(n\leq 10^5,a_i\leq 10^5\)
观察到 \(a_i\) 的范围并不大,可以用 \(O(\sqrt{a_i})\) 的方法枚举出每个数的因子,然后通过一些数组进行统计,不难得到 \(C_a\):满足 \(a\neq b,\ x_b|x_a\) 的 \(b\) 的数量。
如果没有 \(a,b,c,d\) 不等的条件,只需要考虑 \(a,c\) 的组合,\(b,d\) 的情况为 \(C_a\times C_d\), 总的答案也很好算。
\(a,b,c,d\) 不能相等,考虑容斥。先按照 \(a,c\) 不等,其它随意算出答案 \(ans1\),然后减去 \(a\neq c,b=d\) 的数量 \(ans2\),再减去 \(a\neq c,b\neq d,a=d\) 的数量 \(ans3\) 和 \(a\neq c,b\neq d,b=c\) 的数量 \(ans4\),最后发现 \(a\ne c,a=d,b=c\) 的被减了两次,算出这部分的数量 \(ans5\)。最后答案为 \(ans1-ans2-ans3-ans4+ans5\)。\(ans2,3,4,5\) 的计算都类似,不赘述。
容斥的过程稍微有点繁琐,考场上写了对拍,大概是对的。但没考虑到最后答案会超出 \(long\ long\) 的范围......得用 \(int128\) 或者用两个 \(long\ long\) 拼接小小地高精度一下。
H
题意:有 \(n\) 个魔法球和 \(n\) 个空盒子,第 \(i\) 个魔法球的魔法值为 \(a_i\)。现在要将球装入盒子中,每个盒子最多装一个,也可以空着,每个球也最多放入一个盒子中,且相邻的盒子不能放魔法值相同的球。初始体力值为 \(k\),将第 \(i\) 个球装入第 \(j\ (j\leq i)\) 个盒子中消耗 \(i-j\) 体力值。最后放了球的盒子权值 \(v_x\) 为球的魔法值,没放球的盒子 \(v_x=-1\),在保证体力值 \(\ge 0\) 的情况下请移动球使得 \(v_1,v_2,v_3...v_n\) 的字典序最大。
做法挺简单暴力。让字典序最大,自然从 \(1\) 开始往后遍历。遍历到 \(x\) 时,需要找到 \([x,x+k]\) 区间内没被装掉的球里最大的且在所有最大的球里最靠左的那个(尽量节省体力),并把它装入 \(x\)。用线段树维护区间最大值以及区间最大值所在最左端的位置即可,每次执行区间查找、单点修改操作。
但是相邻的两个不能相同,所以还得维护严格次大值和严格次大值最左端的位置,只是让区间合并变得更复杂一些。
复杂度 \(O(n\log n)\)。