Educational Codeforces Round 173 (Rated for Div. 2)
upd:2024/12/18 更新了 G
A
硬币肯定是能拆则拆。时间复杂度 \(O(T\log_{4}n)\) 。
B
分类讨论 \(5\) 个奇数:
- 对于 \(1\) ,肯定可以整除。
- 对于 \(3\) ,可以整除 \(n\) 要求 \(n\) 的数位之和为 \(3\) 的倍数。也就是 \(dn!\equiv 0 \pmod{3}\) 。发现当 \(n \geq 3\) 的时候,\(n!\) 已经是 \(3\) 的倍数肯定满足条件。如果 \(n <3\) ,直接计算是否是 \(3\) 的倍数即可。
- 对于 \(5\) ,要求 \(d=5\) 。
- 对于 \(7\) ,发现 \(111111\) 是 \(7\) 的倍数,也就是说一旦 \(n!\) 为 \(6\) 的倍数也就是 \(n \geq 3\) ,那么肯定满足条件。如果 \(n<3\) ,直接计算是否是 \(7\) 的倍数即可。
- 对于 \(9\) ,做法类似于 \(3\) 。
时间复杂度 \(O(T)\) 。
C
假设全部的数字都满足 \(a_i \in \{-1,1\}\) ,此时的答案可以取哪些数?
求出最大,最小子段和(可以为空),设他们的值分别为 \(mn,mx\) 。可以证明的是,答案可以取遍 \([mn,mx]\) 之间的任何数。证明:
-
取最大子段和的全部前缀(可空),至少可以取遍 \([0,mx]\) 之间的任何数。
-
取最小子段和的全部前缀(可空),至少可以取遍 \([mn,0]\) 之间的任何数。
现在加入 \(a_p \neq \{-1,1\}\) 。那么对于 \(a[1 \dots,p-1]\) 和 \(a[ p+1\dots,n]\) 的答案都可以通过上述算法解决。
剩下的就是那些 \(l \leq p \leq r\) 的区间了。我们求出包含 \(p\) 的最大子段和 \(mx\) 和最小子段和 \(mn\) ,那么答案也可以取遍 \([mn,mx]\) 之间的任何数,证明类似。求的具体方法就是求出 \(a_{p-1}\) 结尾的最大/最小后缀和 \(a_{p+1}\) 开头的最大/最小前缀和。
将满足条件的数排序并去重即可。时间复杂度 \(O(Tn \log n)\) 。
D
求出一个极大的区间 \([x,y]\) 满足 \(l \leq xG \leq yG \leq r\) 。接下来问题转化为了找到两个值 \(p,q \in [x,y]\) 且 \(\gcd(p,q)=1\) ,最大化 \(|p-q|\) 。
直接猜 \(p\in [x,y]\cap [x+\log y] ,q \in [x,y] \cap [y-\log y,y]\) 然后过了。时间复杂度 \(O(T \log^3 V)\) 。
(bro把 \(\log\) 开 \(40\) 然后赛后被hack了,但是开到 \(64\) 即可通过)
E
这个题目很好!
首先二进制问题是可以拆位的,问题转化为了01矩阵问题。我们可以进行的操作有:行涂 \(0\) ,列涂 \(1\) ,问矩阵 \(A\) 是否可以变成矩阵 \(B\) ?
假设不考虑 \(A\) 的状态,仅考虑 \(B_{i,j}\) 的状态:
-
\(B_{i,j}=1\) ,那么第 \(i\) 行涂 \(0\) 应该在第 \(j\) 列涂 \(1\) 之前操作。
-
\(B_{i,j}=0\) ,那么第 \(i\) 行涂 \(0\) 应该在第 \(j\) 列涂 \(1\) 之后操作。
如果将上述关系连边,最终是一个 DAG 就有解。这真的对吗?
我们发现错误原因在于认为每一行,每一列都操作,但是这是不对的。我们引入一个超级源点,连向哪些必要操作的点(\(A_{i,j} \neq B_{i,j}\)):
-
\(A_{i,j}=0,B_{i,j}=1\) ,则必须进行列涂 \(1\) ,源点向其连边。
-
\(A_{i,j}=1,B_{i,j}=0\) ,则必须进行行涂 \(0\) ,源点向其连边。
仅考虑超级源点可以到达的点构成的导出子图,如果是一个 DAG 就有解。现在很对。
对于每一个二进制位都判断以下,时间复杂度 \(O(n^2 \log V)\) 。
F
动态dp题,出的很烂。问题取反面:选取不为空的,尽量小的集合使得异或和为 \(0\) 。
考虑问题放到线段树上,每一个节点维护 \(f_i\) 表示异或和为 \(i\) 的最小节点数,\(g_i\) 表示可以到达最小节点数的方案数。容易在 \(O(\log^2 V)\) 的时间内合并两个节点。
则直接使用线段树来做,预处理 \(O(n \log^2 V)\) ,查询 \(O(q \log n\log^2 V)\) ,无法通过。
考虑猫树分治,预处理是 \(O(n \log n \log V)\) ,查询 \(O(q \log^2 V)\) 。
G
这个题目的做法很有参考价值!
我们考虑分块去做。将答案拆分为块内的答案和块外的答案。只要维护了 \(sum_{i,j}\) 表示元素 \(i\) 在前 \(j\) 个块中出现的次数,配合一个桶很容易去以 \(O(\frac{n}{B})\) 的时间去计算块外的答案(在已知块内答案的基础上),其中 \(B\) 是块长。
对于块内的问题,我们考虑直接维护数组 \(f_{i,j}\) 表示第 \(i\) 个块到第 \(j\) 个块的答案。可以直接以 \(O(\frac{n^2}{B})\) 的时间暴力预处理,考虑点修对 \(f\) 的影响:转化为减少某一个元素/添加某一个元素。这里拿添加元素举例。
假设添加元素 \(v\) 的下标所在块是第 \(x\) 个块,则对于 \(i \leq x \leq j\) ,\(f_{i,j}\) 的权值应该增加 \(sum_{v,j}-sum_{v,i-1}\) ,蛮力维护的时间为 \(O(\frac{n^2}{B^2})\) ;我们还需要维护 \(sum\) 本身的变化,直接蛮力维护时间复杂度为 \(O(B)\) 。
现在分析一下时间复杂度,预处理为 \(O(\frac{n^2}{B})\) 。对于询问,如果是点修,时间复杂度为 \(O(B+\frac{n^2}{B^2})\) ;区间查询时 \(O(B)\) 。发现取 \(B=n^{\frac{2}{3}}\) 时最优秀的,时间复杂度来到了 \(O(Qn^{\frac{2}{3}})\) 。
但是很遗憾,这是无法通过的。
我们想一下哪里不优的?明明两种询问的操作次数可以被视为相同,但是在点修时,维护 \(f\) 花了 \(O(\frac{n^2}{B^2})\) 的时间,而在查询时,只花费了 \(O(1)\) 的时间去调用 \(f\) 。
考虑将 \(f_{i,j}\) 增加 \(sum_{v,j}-sum_{v,i-1}\) 转化为增加 \((sum_{v,j}-sum_{v,x})+(sum_{v,x}-sum_{v,i-1})\) .前后部分分别维护,拿前半部分举例,我们枚举 \(j\) ,对于一个相同的 \(j\) ,\(f_{i \leq x,j}\) 都需要增加 \(sum_{v,j}-sum_{v,x}\) ,直接将贡献打在差分数组上。查询的时候暴力计算差分数组的前缀和,因为差分数组只有 \(O(\frac{n}{B})\) 这么大。
至此,点修的时间复杂度被优化到 \(O(B+\frac{n}{B})\) ;区间查询的时间复杂度变慢了,是 \(O(B+\frac{n}{B})\) 。容易看出 \(B=\sqrt n\) 时最优,时间复杂度为 \(O(Q \sqrt n)\) 。

浙公网安备 33010602011771号