2022 第一轮省队集训 Day5
75+30+20。
T1
T2
先考虑 \(a_i\le 2\) 怎么做,我们枚举每种可能的值 \(x\),然后计算以它为绝对众数的区间。将 \(=x\) 的位置标记为 \(1\),\(\neq x\) 的位置标记为 \(-1\),我们要算的就是某个区间内有多少子区间满足它的区间和 \(>0\)。
处理出来标记的前缀和 \(s_i\),那么要算的就是一段区间内有多少子区间 \([l,r]\) 满足 \(s_r>s_{l-1}\)。这就是区间逆序对,莫队就行了。
对于没有特殊限制的数据,我们枚举每种权值 \(x\)。按照 CF1446D2 的做法,我们标记每个 \(x\) 左右第一个未被标记的非 \(x\) 位置,那么没被标记的地方一定不会对答案产生贡献。对于每个被标记的极长段跑上面说的莫队。设段数为 \(k\),这样做是 \(O(km+n\sqrt{m})\) 的。
注意到这里的瓶颈实际上是:对于每一个连续段,我们都需要扫一遍所有经过这个连续段的询问。考虑根号分治,对于 \(>\sqrt{n}\) 的段直接莫队。对于 \(\ le \sqrt{n}\) 的段,我们枚举其中的子区间 \([l,r]\),然后将这个区间的贡献直接放到平面上。把所有的小段都放完以后,堆在一起做一次扫描线,要支持的是 \(O(n\sqrt{n})\) 次区间加和 \(O(m)\) 次区间求和,根号平衡即可。
假如 \(n\sim m\),总的时间复杂度就是 \(O(n\sqrt{n})\) 的。
T3
似乎是什么“半平面莫队”。
神秘题
给定序列 \(\{a_n\}\),有 \(q\) 次操作:
- 对一段下标为等差数列的位置加一个数;
- 或者询问这些位置的和。
考虑按时间分块,设每 \(B\) 个修改操作分一块。当我们扫过 \(B\) 个修改后,我们将它们都插入到数据结构中。那么,对于每个询问,影响它的修改分为两种:
- 数据结构中的;
- 当前散块中的。
然后咋做啊!!!!!!!!!!!!!
下面是 qyc 专场!
如何 \(O(1)\) 求两个等差序列的交的长度?我们设它们的起始位置分别为 \(a_1,a_2\),公差为 \(d_1,d_2\)。我们有 \(d_1,d_2\le n\)。
那我们实际上是要合并两个同余方程,然后就能 \(O(1)\) 算出交的长度了:
写成不定方程的形式,也就是 \(d_1x-d_2y=a_2-a_1\)。用 \(O(1)\) \(\gcd\) 的方法,将两边同时除以 \(\gcd(d_1,d_2)\),这样 \(d_1\perp d_2\)。
考虑将所有这 \(O(n^{5/3})\) 个同余方程离线,并把它们都挂到 \(d_2\) 的 vector 中。解这个同余方程就相当于求 \(d_1\) 在 \(\bmod d_2\) 意义下的乘法逆元。对于每个 \(d_2\),我们可以在 \(O(C+\log d_2)\) 的时间复杂度内算出所有逆元,其中 \(C\) 是 \(d_2\) 的 vector 的长度。所以总时间复杂度是 \(O(n^{5/3}+n\log n)\),均摊到单个同余方程就是 \(O(1)\)。
CTS 2022 袜子
半平面逆序对
平面上有 \(n\) 个点 \((x_i,y_i)\),每次给定直线 \(Ax+By+C=0\),求所有满足 \(Ax_i+By_i+C<0\) 的 \((x_i,y_i)\) 中,有多少对 \((i,j)\) 满足 \(x_i<x_j\land y_i>y_j\)。
对于每个 \((x_i,y_i)\) 预处理有多少个 \(j\) 使得 \(x_i<x_j\land y_i>y_j\),记作 \(f_i\)。假如直线的斜率 \(>0\),答案就是半平面中所有点的 \(f_i\) 之和。否则,我们再预处理 \(g_i\) 表示顺序对的个数,设 \(c\) 为半平面中点的个数,答案就是 \(c(c-1)/2-\sum_{i\in \text{half plane}} g_i\)。
单次 \(O(\log n)\) 区间线性基
给定正整数序列 \(\{a_n\}\),每次询问一段区间的线性基。
扫描线,每次将右端点 \(r\) 向右移。维护 \(p_i\) 表示当 \(l\le p_i\) 时,线性基中的第 \(i\) 位有值。再维护 \(a_1\sim a_r\) 的线性基,线性基的第 \(i\) 位设为 \(B_i\)。
当新插入一个元素 \(a_r\) 时,贪心地将其在线性基上从高位到低位遍历。假如遍历到某一位的时候,\(a_r\) 在这一位上的值是 \(1\),那么将这个位置的 \(p_i\) 赋值成 \(r\),并且用 \(B_i\) 原来的值继续向低位遍历。这样,所有满足 \(p_i\ge l\) 的 \(B_i\) 组成的线性基,就是 \(a_l\sim a_r\) 的线性基。
例题:CF1100F Ivan and Burgers。
P4062 [Code+#1] Yazid 的新生舞会 线性做法
和今天 T2 的转化方法差不多。仍然考虑枚举每种值 \(x\),并向左、向右标记。但这里如果用 std::set
的话就带 \(\log n\) 了。考虑我们要支持什么:
- 删除一个位置;
- 询问一个位置前面最靠后的一个未被删除的位置。
可以直接并查集维护,\(O(n\alpha(n))\),听说这里的 \(\alpha(n)\) 可以干掉。
然后对每一个极长段,我们都需要算出其中的逆序对数量。逆序对并没有线性做法,但这里有一个特殊性质:序列中的每个元素都只会相对于上一个元素 \(\pm 1\)。所以直接开桶维护就行了。
P7889 「MCOI-06」Eert Tuc Knil
线段树合并。
数据随机下的半平面数点
平面上有 \(n\) 个点 \((x_i,y_i)\),\(q\) 次询问,每次给定 \(A,B,C\),求 \(Ax_i+By_i+C<0\) 的 \(i\) 的个数。
把平面分成 \(\sqrt{n}\times \sqrt{n}\) 块,那么每块内期望有 \(O(1)\) 个点。对于横着的每段,预处理前缀和。当一个直线切过来的时候,与它有交的块数是 \(O(\sqrt{n})\) 的,对于这些块内的点,暴力判断即可。对于其他的块,直接用前缀和即可。
时间复杂度 \(O(q\sqrt{n})\)。