2024.9 做题记录
001. CF2002E Cosmic Rays CF*2300
标签:思维,栈
题意:
给定
- 在第
个位置的数字 的位置
问每个前缀最多成操作多少次。
Observation:
- 问每个前缀最多能撑住几轮操作,其实暗示我们利用前面的答案以某种方式推出后面的答案。
- 手玩样例可以发现,如果对于
个元组, 全都不相同,那么答案即为 。证明也是比较显然的。 - 我们考虑处理权值相同的情况,我们简化问题进行讨论——只考虑两个权值相同的块夹着一个不同权值块的情况。将三个块的大小设为
。如果 ,那么根本不会有任何贡献,答案还是前面的。如果 且 ,那么其实就会加上这个块的贡献,不过这种情况我们在代码中其实是可以直接压进去不管的。如果 且 ,那么就会把 消了,然后 和 拼在一起。然后这个串可以撑住的轮数就变为了 。 - 两个权值相同夹着中间的块不管是什么,我们只需要知道它能撑住的轮数即是它的
。
Doubt:
想到这里就感觉想不下去了。当时的想法是因为看到标签里有 dp,看怎么样能找到前面相同的权值然后用数据结构优化一下。结果解法是栈,有些震惊。
Solution:(after seeing le0n's tutorial)
有点像单调栈的意思。
- 如果前面的块大小比你现在压进来的小,那他根本就没用,直接更新一下现在消了的次数然后直接从栈里踢出去即可。
- 如果权值和自己相同,更新自己的大小为
,这根据的是性质 。然后把这个块踢出去,为什么呢?因为你自己合并之后还会压进来更大的块。 - 其他情况就不能吞或合并了,因为人家比你的大小大,你影响不了人家。
- 把自己这个更新后的元组压进栈,最大值更新,做完了。
002. CF906D Power Tower CF*2700
标签:扩展欧拉定理
虽然 2700 但不怎么难的题。
扩展欧拉定理降幂塔的另一大板子(第一个是上帝与集合的正确用法)。
题意:
给定数组
Observation:
- 看到幂塔,想到扩展欧拉定理+快速幂的光速幂解法。
函数的层数是 级别的,也就是说每次询问的复杂度都是双 (有一层快速幂)。而 变为 后上面的也不用管了。(上一个板子的结论)- 发现需要用到的
值就那么几个,完全可以根号 单点查,或者提前预处理(推荐这个)
Solution:
- 预处理出要使用的模数
- 递归处理询问(DFS)
- 快速幂略有不同,大于
需要模 再加 。 - 暴力计算即可
003. CF242E XOR on Segment CF*2000
标签:线段树,位运算
题意:
在一个序列上做两种操作
- 询问区间和
- 区间异或
Solution:
比较经典的一个 trick 吧。关于区间位运算的,就考虑状压线段树或者拆位线段树。这里拆位线段树比较好写,于是就写了空间开销较大的拆位。
对于数的每一位维护一颗线段树。
- 于是对于修改操作——异或
。就是把 拆成二进制数,如果 这一位为 ,那么就没有改变,否则在区间线段树上,这一位全部取反。而其和的变化就是 变为了 。懒标记记录这个区间是否翻转即可,下传操作是显然的。 - 对于求和,显然的,就是
另外注意建树的时候,每一位都要 PushUp 就好。
004. CF438D The Child and Sequence CF*2300
标签:线段树,势能分析
题意:
在一个序列上做三种操作:
- 询问区间和
- 区间对
取模 - 单点修改
Observation:
- 发现一个势能性质就好,就是区间取模次数是
级别的,于是进行类似 GSS4 的暴力单点改就好 - 什么时候不改?显然的,区间最大值小于
就不改。
Solution:
- 对于操作
,维护区间 。 - 对于操作
,如 observation 所提到的,进行单点暴力修改。 - 对于操作
,暴力修改。 - 记得 PushUp,但因为没有懒标记,所以不用 PushDown。
005. CF434D Water Tree CF*2100
标签:线段树,树链剖分
题意:
给出一棵以
- 将点
和其子树上的所有节点的权值改为 。 - 将点
到 的路径上的所有节点的权值改为 。 - 询问点
的权值。
Solution:
就,就直接树链剖分。注意处理
点查询的话,其实维护区间和就好,并没有必要为了点查询进行额外的麻烦操作。
区间改
006. CF600E Lomsat gelral CF*2300
标签:线段树合并
题意:
有一棵
Solution:
考虑对每一个节点建一棵权值线段树,而每次算贡献其实就是将自己节点的权值线段树向自己的父亲合并。而权值线段树所要维护的就是出现次数的最大值和最终的答案。
如何计算这个节点总的答案?很简单,就是
唯一要注意的细节就是权值线段树的合并问题,还有加点较为麻烦,更新部分可以考虑加一个 PushUp 函数减小码量。
007. UVA437 The Tower of Babylon 提高+/省选-
标签:拆点,动态规划
看紫书看到这么个题,于是就混进来一道 Uva。
题意:
有
Solution:
其实还是挺简单的,首先由于可以翻转,考虑把
注意到题目中是天然的二维偏序关系,于是这个图是一个 有向无环图。在这个 DAG 上面跑 Toposort 求出最长路即可。
最后答案是所有的
008. CF1209G1 Into Blocks (easy version) CF*2000
标签:并查集,STL-set
题意:
给定序列
Observation:
- 我们发现,相交的区间和不交的区间有本质区别。于是先想到维护每个权值的左右端点。
- 在一群相交的线段里面,所花费的最小代价就是区间长度减去数最多的一个权值的个数。
- 把所有贡献加起来就是答案。
Solution:
- 考虑经典 Trick,使用 set 的神奇排序维护区间交,并使用 dsu 并查集把交的线段放一个集合里。
- 怎样维护区间求交?详见会场预约那题。大概就是:
bool operator < (const Line &x) const
{
return R < x.L;
}
然后如果交就会判定为相等,但是其实有点细节。比如合并的这段代码:
int minn = ll[i], maxn = rr[i];
while(pos != s.end())
{
Union(i, (*pos).id);
minn = min(minn, (*pos).L);
maxn = max(maxn, (*pos).R);
s.erase(pos);
pos = s.find(Line{ll[i], rr[i], cnt[i], i});
}
s.insert(Line{minn, maxn, cnt[i], i});
要维护
- 后面就是暴力统计就行。
这做法比较 naive,貌似还有更好的做法。
009. P3071 [USACO13JAN] Seating G 省选/NOI-(真实难度 提高+/省选-)
标签:线段树,区间合并线段树
题意:
有一排
求
Solution:
如果不是连续的,也有另外一种做法,就是二分 + 线段树,这种要求连续的更难一些。
其实与 GSS3 区间最大子段和非常像甚至还弱化了。在一个
线段树的 PushUp 是难点,但是被 GSS3 完美覆盖了,所以直接上代码:
if(Sgt[lc(p)].anscnt == Sgt[lc(p)].R - Sgt[lc(p)].L + 1) Sgt[p].Lcnt = Sgt[lc(p)].anscnt + Sgt[rc(p)].Lcnt;
else Sgt[p].Lcnt = Sgt[lc(p)].Lcnt;
if(Sgt[rc(p)].anscnt == Sgt[rc(p)].R - Sgt[rc(p)].L + 1) Sgt[p].Rcnt = Sgt[rc(p)].anscnt + Sgt[lc(p)].Rcnt;
else Sgt[p].Rcnt = Sgt[rc(p)].Rcnt;
Sgt[p].anscnt = max(max(Sgt[lc(p)].anscnt, Sgt[rc(p)].anscnt), Sgt[lc(p)].Rcnt + Sgt[rc(p)].Lcnt);
建树和更新的时候细节都有些多,需要想清楚。
下一步是求连续区间左端点。
- 如果其左子树的最长
连续段已经大于等于要求,那么优先递归左子树(要求编号最小)。 - 如果恰好跨过中间,也就是左子树的
加上右子树的 是大于等于要求的话,那么就返回 减左子树的 再加 ,这很好理解。 - 否则就是在右边,递归右子树。
复杂度?这样只会递归一边,复杂度是必定有保证的。是一种 类似线段树二分 的方法。
有个双倍经验是 Hotel G。
010. P2962 [USACO09NOV] Lights G
标签:高斯消元
题意:
给出一张
你可以操作任意一个点,操作结束后该点以及所有与该点相邻的点的状态都会改变,由
你需要求出最少的操作次数,使得在所有操作完成之后所有
Solution:
看到
因为我们考虑且仅考虑其在模
最后如果没有自由元的话答案就是
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】