2021 年 7 月 7 日提高组模拟赛题解
A : 最大子段和
题目描述
给定一个长度为 \(n\) 的数列 \(a\) ,从这个序列中选出不相交的两个连续段,要求它们的和最大,请你求出这个最大的和。具体的,你需要给出 \(A,B,C,D\) ,满足 \(1 \leq A\leq B < C \leq D\) ,并且最大化下面的式子:
\(1 \leq n \leq 10^5 ,1 \leq |a_i| \leq 10^5\) 。
Solution
考虑枚举分界点 \(k\) ,使得所选的区间 \([A,B]\) 在 \(k\) 的左边(可以包含 \(k\) ,即 \(B \leq k\)),所选的区间 \([C,D]\) 在 \(k\) 的右边(不能包含 \(k\) ,即 \(C>k\)),因为分成的这两部分完全独立,所以可以分别求出这两部分的最大子段和,即可求出以 \(k\) 分界的最大子段和。
另 \(k\gets1,2 \dots n-1\) ,求出所有 \(k\) 的最大值即可。
至于求最大子段和,可以用 DP 分别预处理前缀最大子段和和后缀最大子段和。
时间复杂度 \(\mathcal{O}(n)\) 。
B : 序列
给定一个长度为 \(n\) 的序列 \(a\) ,初始值全部为 \(0\) , \(m\) 次操作,每次操作有 \(4\) 个参数 \(l,r,s,e\) ,表示将区间 \([l,r]\) 加上一个首项为 \(s\) ,末项为 \(e\) 的等差数列。
求出操作完成之后数列的每一项,为了避免输出过多,你只需要输出数列的异或和。
\(1 \leq n ,m \leq 5 \times 10^5,2s\),保证任何时候输入和数列的数在 long long
范围内。
Solution
把原序列差分,设差分之后的数组为 \(b\) ,在区间 \(l,r\) 加上一个首项为 \(s\) ,末项为 \(e\) ,公差为 \(d\) 的等差数列,可以发现: \(b_l\gets b_l+s,b_{r+1}\gets b_{r+1}-e\) ,同时对于 \(l+1\leq i \leq r - 1\),\(b_i \gets b_i+d\) 。
于是把差分数组再次差分,即可 \(\mathcal{O}(1)\) 实现区间加。举个例子,设再次差分的数组为 \(f\) ,在区间 \(l,r\) 加上一个首项为 \(s\) ,末项为 \(e\) ,公差为 \(d\) 的等差数列,\(f\) 的变化为:
最后对再次差分的 \(f\) 数组做两次前缀和,即可得到原数组。
时间复杂度 \(\mathcal{O}(n)\) 。
C : 柠檬
给定 \(n\) 个集合,第 \(i\) 个集合初始只包含元素 \(i\),开始时所有元素的权值为 \(0\) ,有 \(m\) 次操作:
- 合并元素 \(x\) 所在的集合和元素 \(y\) 所在的集合。
- 令 \(x\) 所在集合的所有元素的权值加上 \(k\)。
操作完后输出所有元素的权值。
\(1 \leq n ,m\leq 5 \times 10^5,1 \leq k \leq 100\)。
Solution1
考虑线段树合并。用并查集维护每一个元素所对应的树根是哪个。对于合并操作,直接合并两个元素所对应的线段树。
对于整个集合加上一个数的操作,直接对于整个子树打上一个标记即可。记得在合并和查询的时候下方标记。
时间复杂度 \(\mathcal{O}(n \log n)\)。
Solution2
把每个集合看成是一棵树,那么所有集合构成了森林。
对于合并操作,建立一个虚点 \(p\) ,令 \(x\) 所在子树的根节点和 \(y\) 所在子树的根节点的父亲都指向 \(p\) 。
对于整个集合加上一个数的操作,直接在这个子树的根节点打上一个标记即可。
最后从每一棵数的根节点开始 DFS ,自顶向下累加标记,当访问到元素 \(x\) 时,累加的标记就是 \(x\) 的值。
时间复杂度 \(\mathcal{O}(n)\)。