E 题目总结
399 E
我们可以发现一些性质,将所有字母看作点,每个点的出度不能大于 1
以及一旦成环,需要用一个额外的点,先拆为链才能继续
\(n\) 个点 \(n\) 条边,这个条件也就是我们熟悉的由环构成的图
找到有几个环,然后每个环加上 \(1\) 点贡献
并且需要特判一下,涉及到 26 个字母时无法转化
396 E
拆位,将每一位分别考虑
\(Z_j\) 的第 \(i\) 位是 \(0\) 还是 \(1\) 表示 \(A_{X_j}\) 与 \(A_{Y_j}\) 的第 \(i\) 位相同还是不同
将这些关系用图表示出来,就是 \(A_{X_j}\) 和 \(A_{Y_j}\) 存在一条权值为 \(0\) 或 \(1\) 的边
之后对图染色,将当前图分为两个部分,贪心的让数量少的那部分作为当前位为 \(1\) 的数(也可以用带权并查集)
395 E
分点 \(dijkstra\)
将每个点分为两种情况,未翻转的到该点的最短距离,以及翻转之后到该点的最短距离
然后写出 \(dijkstra\),元素是 {距离, 点的序号, 状态},懒得写 struct,将距离取负数
394 E
由于每找到回文字符串的一个相同头尾,可以得到一个长度增加 \(2\) 的回文字符串
可以用 BFS 找到最小的距离,就是连接两个点的最短回文字符串
先将 {i, i} 放入 \(queue\) 中,并将ans[i][i] 初始化为 0
然后将从 u 到 v 的边放入 \(queue\) 中,ans[u][v] = 1
这样,依据 \(queue\) 先进先出的道理先考虑距离短的
接下来类似与 \(dij\),可以得到连接的最短回文字符串
393 E
调和级数预处理 \(O(MlogM)\)
用 \(i\) 位置累加,可以知道 \(i\) 可以作为多少数的因数
这样,当 \(t_i\) 大于等于 \(k\) 的时候,表明,这个数可以是选 \(k\) 个数之后的公因数
392 E
刚开始可以用 \(dfs\) 或者 \(DSU\) 找到所有连通块,用一个 vector 存起来
接下来,要用那些富余的边(成环的边)来连接各个连通块
因为要输出如何连接,需要找到一种可行的连接方式
遍历所有边,为每条边找到一个不在同一集合的点,连接这两个点,并用并查集连接这两个集合
利用双指针算法,一个遍历所有多余的边,一个遍历所有点
如果当前点在大块上,就找到不在一块的点
如果不在同一块,将点所在的块与边对应的连通
如果这条边在大块上,找到其它块的点
如果不在大块上,将边所在的连通块并入大块
391 E
DP,用递归或者循环实现
用一个 array<int, 2> 来记录分别到达 0、1 需要的耗费
从三叉树的叶子节点,通过状态转移,得到根节点需要的耗费
390 E
背包问题
先用01背包预处理三种维生素,得到消耗 \(i\) 个能量得到的最多的维生素
然后枚举出能量分配的所用方法,用背包得到答案
389 E
一种常见的套路,单价线性增加或减少,需要贪心的找到最大或者最小的单价
用单价来二分,由于还存在单价相同,但只会取一定数量的相同最高单价的情况
可以用 pair<int, int> 二分,传递两个参数(总和,数量),找到符合的答案
二分完之后,由于此时的 l 是刚好符合的一个答案,一旦 l 更大,就刚好 sum 就会超过(因为 l + 1 的数量超过了极限)
所以再考虑,单价为 l + 1 的个数
亦或者,可以在二分时直接处理总价,如果总价超出了返回 0
没有超出的话,默认可以取一定数量的 x + 1 的单价的物品
388 E
可以用二分的方法解决,二分产生的对数
发现,成对的一定是 i 与 n / 2 + i 结合
或者用双指针,一个考虑前半部分,一个考虑后半部分
找到符合的后半部分的一个是前面的两倍的数
387 E
能被 3 和 9 整除的数的特征,各个数位的和能被 3 或 9 整除
能被8整除的数,一个整数的末3位若能被8整除,则该数一定能被8整除
被 4 整除时最后两位数字构成的数能被 4 整除
386 E
条件二项式系数小于 1e6 也就是从 n 个数中取 k 个的组合数
是一个深搜加剪枝的问题,用等效性剪枝将 \(n^k\) 压缩到 \(\binom{n}{min(k, n - k)}\)
也就是说,如果 n - k < k,从选取 n - k 个排除
385 E
遍历中心节点,通过枚举中心节点周围节点的数量来得到答案
将中心节点周围节点通过边数从大到小排序,从大的开始选起然后求雪花的最大值
384 E
单调队列优化BFS,每次贪心的连接最小的相邻粘液
由于是不限次数的连接,所以用 priority_queue 来直接优化就可以
383 E
Kruskal 算法与贪心结合
将所有边按照边权从小到大排序,连接所有边
如果两边是不同的连通块,此时连通块内 A 与 B 中元素互相连接
也就是 min(cnta[u], cntb[v]) + min(cnta[v], cntb[u]) 对得到了对应的路径最大边
将这些元素从两个连通块中减去,并连接两个连通块
jly 延迟的存取一个连通块中两个元素的最短路径
382 E
首先,利用概率DP,求出得到每包得到 i 个稀有款的概率
然后推出期望的式子,枚举得到 i 稀有的期望,求得答案
381 E
首先将 '/' 的位置都找到,存在 set 里
用前缀和处理 '1' 和 '2' 的个数,以实现区间查询
对于每个查询,查询区间内的 '/' 位置,用二分找到两边 1 和 2 的数量最接近的点
380 E
可以用 set 模拟所有区间,每次二分找点,直接修改区间的颜色
用一个数组记录所有颜色的个数,修改的时候改变这个数字
然后被修改的区间向左向右找两个区间,看看需不需要合并
如果用并查集的话,将区间的第一个点作为根节点,把颜色存储在这个位置(bool merge(...) 没有 return true)
用 DSU.size() 可以找到下一个区间的节点
379 E
可以发现对于从左到右第 i 个数字,相当于 \(0 \sim n-i-1\) 位增加 \(i + 1\)
可以用差分线性实现,然后用类似于高精度的方法把数舒展开来
时间复杂度可以达到 \(O(N)\)
378 E
用前缀和处理一下,并且取余
发现想求区间和的余数,相当于 m * 需要进位的左边余数 + 当前位 * (i + 1) - 左边所有位之和
发现所有需要进位的左边余数个数之和就是逆序对的个数,需要用一个线段树或者其它的什么东西来得到答案
377 E
由于 \(P_i~~!=~P_j (i < j)~\) 并且 \(~1 \leq P_i \leq N\)
所以最后的图是一个由一些环构成的,所以它们的状态是在环上转换,可以用模拟找到规律
在环上的位置差为绕环方向第 \(2^k\) 个元素
如何实现,对每个环遍历一遍,位置存入 vector
由于环上的值都已经被储存,再用这个更新 p 的值,把 \(p_{a_x}\) 更新为 \(a_{x + 位移差}\)
376 E
按照 \(A_i\) 的大小排序,从小到大,假设选第 \(i\) 个 \((i \geq k - 1)\)
那么找到前面选 \(k - 1\) 个数,\(B_i\) 和的最小值,可以用 multiset 或者 priority_queue 模拟
375 E
数据范围比较小,总和 1500,个数 100
用 DP 解决问题,只需要考虑两个队伍的数值
因为知道两个队伍有哪些人之后,剩下的人就是第三个队伍的
对每个人归哪个队进行讨论,状态表示是 DP[i][j][k] ,第 i 个人,第一队的总价值 j, 第二队的总价值 k
374 E
一眼可以看出要用二分,然后要考虑限定了最低产量,每组物品怎么选花费最低
由于限定了从两种机器种选,并且两种机器的产量都低于 \(100\),就可以发现一个现象
性价比比较低的那个机器,选择最多不超过 \(100\) 个
因为另一种机器的产量也不超过 \(100\)
如果选择这个机器达到一定数量,可以用另一种机器替换,并且花费更低
这样,枚举从 \(1 \sim 100\) 的所有个数,再把剩下的产量用另一机器实现
373 E
372 E
并查集,并用一个 set 数组来存连通块中的元素
需要计算一下时间复杂度,以及空间复杂度,发现对并查集之间进行连接需要 \(O(log N)\)
最后时间复杂度应该是 \(O(N~logN~logN)\)
空间复杂度大约是 \(O(N~logN)\)
改装 DSU,由题可知,k <= 10,用迭代器 + prev 线性得到第 k 大的值
371 E
从数据范围明显能得出,需要用到一个线性或者时间复杂度低的算法
刚开始倾向于双指针,找到 \(a_i\) 的作用域,用差分之类找到那些让次数增加的区间
之后发现这并不妥,因为题目的问题更倾向于所有区间
然而,发现不管什么做法关键都是找到上一个相同值的位置
想到了找到包括了 \(a_i\) 的区间,也就是用区间左端点可能的值个数乘以右端点可能值的个数
很明显右端点可以由 \(i\) 一直到 \(n\),左端点是上一个 \(a_j == a_i\) 的 \(j\) 到 \(i\),这些区间由于 \(a_i\) 的加入而增加了区间中数的种数
370 E
369 E
用 Floyd 算法,先计算出所有点到点的最短距离(三重循环for(中间点 for(起点 for(终点 )
看到提供的边数非常小,题意要求至少走过一次,暴力求解走过这些边所有顺序所有方向的走法
用处理好的点到点最短距离得到需要的时间