第十二届蓝桥杯大赛软件赛省赛第二场 C/C++ 大学 A 组 题解
A. 双阶乘
输出 \(2021!! \bmod 10^4\)
for 循环每次减 \(2\) 即可
B. 格点
求第一象限整点中,\(xy\leq 2021\) 的整点个数
for 循环暴力遍历 \(2021\times 2021\) 的平面,统计答案即可
C. 整数分解
求 \(2021\) 分解为 \(5\) 个正整数的有序分解方案数
令 \(f_{n, p}\) 表示 \(n\) 被分解为 \(p\) 个正整数的有序分解方案数
搜索或递推均可
D. 城邦
给定编号为 \(1\)~\(2021\) 的 \(2021\) 元完全图,定义点权为编号数码的集合的元素和(例如 : \(2021\) 的为 \(2+0+1=3\))。
定义连接两点 \(a, b\) 的边权为两点点权之和
求 MST 边权和
先暴力把 \(1\)~\(2021\) 的点权跑出来,然后所有边已知
由于是提交答案题,跑 Kruskal 或者 Prim 算法均可
E. 游戏
给定数值 \(n\) ,两人轮流进行游戏。每一轮可将数字 \(n\) 化为其因数之一,直到 \(n\) 变为 \(1\)
问 \(n=20210509\) 时的游戏方案数
令 \(f_d\) 表示从 \(d\) 开始,游戏的方案数,初始 \(f_1=1\)
用刷表法,将 \(d\) 的所有倍数 \(n\) ,均执行 \(f_n+=f_d\)
复杂度为 \(\displaystyle \sum_{i=1}^n \lfloor{n\over i}\rfloor\approx \sum_{i=1}^n {n\over i}=O(n\log n)\)
期望时长为 \(5s\)
F. 小平方
求 \([1,n)\cap Z\) 中,模 \(n\) 意义下,平方严格小于 \({n\over 2}\) 的数的个数
\(n\leq 10^4\)
for 循环暴力验证即可
G. 完全平方数
给定正整数 \(n\) ,求最小的正整数 \(x\) ,使得 \(nx\) 为完全平方数
\(n\leq 10^{12}\)
考虑到 \(n\) 大于 \(\sqrt n\) 的质因数最多 \(1\) 个
否则任意两个乘起来也超过 \(n\)
因此优先用欧拉筛或埃氏筛打出 \(\sqrt n\leq 10^6\) 范围内的质因数,将该部分的每个质数在 \(n\) 中的次数求出
若次数为奇数,则 \(x\) 中必须出现奇数次该质数,故取 \(1\) 次;否则 \(x\) 中需为偶数次,取 \(0\) 次
最后验证 \(n\) 是否仍有其他质因数,若有,则 \(x\) 中该质因数必须出现奇数次,同样取 \(1\) 次
H. 负载均衡
\(n\) 台计算机,第 \(i\) 台算力为 \(v_i\)
\(m\) 个任务,每个在 \(a_i\) 时刻送达,需要消耗 \(b_i\) 号计算机 \(c_i\) 的时间与 \(d_i\) 的算力
若分配任务时,计算机算力充足,必须执行任务,并输出剩余算力;否则输出 \(-1\)
\(n, m\leq 2\times 10^5\)
考虑将任务拆成两瓣:
- \(a_i\) 时到达的,消耗 \(b_i\) 号计算机 \(d_i\) 算力的
- \(a_i+c_i\) 时到达的,消耗 \(b_i\) 号计算机 \(-d_i\) 算力的
且第二个子任务奏效当且仅当第一个子任务奏效
因此,对任务标记原来的序号 \(i\) ,再按时间排序;时间相同时,算力为负数的任务(第二类任务)优先
维护每台计算机的剩余算力,按时间顺序执行任务
当执行第一类任务时,检查算力是否充足,充足则执行当前任务,更新剩余算力并输出;若不充足,则标记当前任务原来序号 \(i\) 不生效,并且输出 \(-1\)
当执行第二类任务时,检查当前任务是否生效,若不生效则直接退出;否则更新算力
复杂度为 \(O(n\log n)\)
I. 国际象棋
规定国际象棋棋盘中,位于点 \((x,y)\) 的马可以攻击 \(8\) 个方向:
- \((x-2, y-1)\)
- \((x-2, y+1)\)
- \((x-1, y-2)\)
- \((x-1, y+2)\)
- \((x+1, y-2)\)
- \((x+1, y+2)\)
- \((x+2, y-1)\)
- \((x+2, y+1)\)
求 \(n\times m\) 的棋盘中,放置 \(k\) 匹马且不互相攻击的方案数
\(n\leq 6, m\leq 100, k\leq 20\)
状压 dp :预处理 \(n_{1, S}\) 表示当前行状态状态为 \(S\) 时,下一行的最大可选集合;\(n_{2, S}\) 表示下两行最大可选集合;\(cnt_S\) 表示 \(|S|\)
记 \(f_{m, S, T, k}\) 表示第 \(m\) 行状态为 \(S\) 且第 \((m-1)\) 行状态为 \(T\) 时,放置了 \(k\) 匹马且不互相攻击的方案数
不难得出,当且仅当 \(S\subseteq n_{1, T}\) 时方程有意义,且初始状态为 \(f_{1, S, 0, cnt_S}=1\)
状态转移采用刷表实现:将 \(f_{m, S, T, k}\) 刷到 \(\forall R\subseteq (n_{1, S}\cap n_{2, T}),f_{m+1, R, S, k+|R|}\)
答案为 \(\displaystyle \sum_S\sum_T f_{m, S, T, k}\)
发现第一维可以滚动成 \(m\bmod 2\) 形式,故空间复杂度为 \(2\times 2^n\times 2^n\times k=O(k\cdot 4^n)\)
时间复杂度为 \(m\times 2^n\times 2^n\times k+2^n\times 2^n=O(mk\cdot 4^n)\) ,显然充足
甚至加上了 \(S\subseteq n_{1, T}\) 的限制,根本拉不到那么大
J. 完美序列
这题题目是真的绕
定义完美序列为:满足除第 \(1\) 个数外,所有数为前一个数的因数的序列。
定义序列的完美值为:该序列所有完美子序列的长度最大值
求 \(1\)~\(n\) 的所有排列 \(P\) 中,每个排列中,所有长度为 \(\{n, (n-1), (n-2), \cdots , 1\}\) 的完美值的完美序列,它们的元素和
\(T\leq 10^5\) 组独立询问,每次询问 \(n\leq 10^6\)
当 \(n=3\) 时,\(\{3, 2, 1\}\) 的完美值为 \(\{2, 1\}\) 的长度 \(2\)
考虑 \(n=3\) 的所有排列:
- \(\{1,2,3\}\) 不含长度为 \(2\) 的完美序列
- \(\{1,3,2\}\) 不含长度为 \(2\) 的完美序列
- \(\{2,1,3\}\) 含长度为 \(2\) 的完美序列 \(\{2, 1\}\),元素和为 \(3\)
- \(\{2,3,1\}\) 含长度为 \(2\) 的完美序列 \(\{2, 1\}, \{3, 1\}\),元素和为 \(7\)
- \(\{3,1,2\}\) 含长度为 \(2\) 的完美序列 \(\{3, 1\}\),元素和为 \(4\)
- \(\{3,2,1\}\) 含长度为 \(2\) 的完美序列 \(\{2, 1\}, \{3, 1\}\),元素和为 \(7\)
故答案为 \(0+0+3+7+4+7=21\)
先考虑打出 \(f_n\) 表示严格以 \(n\) 开头的完美子序列长度最大值,则有 \(\displaystyle f_n=\max_{d\mid n}f_d+1\)
因此,同上某题也是因数的,用刷表法算出 \(f_n\)
接着,根据定义,\(\{n, (n-1), (n-2), \cdots , 1\}\) 并没有限制开头值,故其完美值为 \(\displaystyle g_n=\max_{i=1}^n f_i\) ,动态刷前缀最大值更新即可
现考虑贡献:设存在某个完美序列 \(v_{1, 2, 3, \cdots, g_n}\)
则元素和为 \(\displaystyle \sum_{i=1}^{g_n} v_i\),在所有排列中出现的方案数为 \(\displaystyle P(n, n-g_n)={n!\over g_n!}\),故贡献为 \(\displaystyle (\sum_{i=1}^{g_n} v_i)\cdot {n!\over g_n!}\)
同时,对于另一个完美序列 \(w_{1, 2, 3, \cdots, g_n}\) ,贡献同样为 \(\displaystyle (\sum_{i=1}^{g_n} w_i)\cdot {n!\over g_n!}\) ,且和 \(v\) 的独立
故需求出所有完美序列的所有元素和:\(A_n\) ,则答案为 \(A_n\cdot {n!\over g_n!}\)
现考虑如何求 \(A_n\) :
先记 \(c_n\) 表示 \(n\) 开头的完美序列个数
刷表求 \(f_n\) 时,考虑由 \(f_d\) 更新 \(f_n\) 的一幕
当 \(f_d+1=f_n\) 时,说明 \(n\) 的后续接 \(d\) 是当前最优的策略之一,故更新 \(\begin{cases}A_n+=A_d+n\times c_d\\c_n+=c_d\end{cases}\)
当 \(f_d+1>f_n\) 时,说明 \(n\) 的后续接 \(d\) 比之前的都更优,故更新 \(f_n=f_d+1\) ,且 \(\begin{cases}A_n=A_d+n\\c_n=c_d\end{cases}\)
同理,后续刷表求 \(g_n\) 时,由于 \(g_n=\max(g_{n-1}, f_n)\)
当 \(g_{n-1}=f_n\) 时,说明以 \(n\) 开始和以某些比 \(n\) 小的数开始都是最优策略,故更新 \(\begin{cases}A_n+=A_{n-1}\\c_n+=c_{n-1}\end{cases}\)
当 \(g_{n-1}>f_n\) 时,说明不以 \(n\) 开始是最优策略,故更新 \(\begin{cases}A_n=A_{n-1}\\c_n=c_{n-1}\end{cases}\)
算法瓶颈在打出 \(A_n\) 与 \(g_n\) 以及阶乘极其逆元,复杂度在于枚举枚举倍数的 \(O(n\log n)\) 和线性扫描的 \(O(n)\)
故总复杂度为 \(O(n\log n+T)\)