康复训练
CF1845E Boxes and Balls
给定长为 \(n\) 的 01 序列和一个整数 \(k\)。每次操作可以选择相邻两个数,满足两个数不相同,然后交换这两个数。求最终能得到多少种不同的序列。
\(n,k\le 1500\)
分析
首先注意到如果我们枚举最终的 01 序列,那么所有的合法的操作方案消耗的步数都是相同的,均为两个序列中第 \(i\) 个 1 出现的位置差的和。暴力的 DP 记录前 \(i\) 个位置选了 \(j\) 个 1 操作步数 \(k\),直接做就是三次方的。
由于状态已经三次方,而且状态看起来不能直接压掉一维信息,考虑发掘一些性质。发现操作次数的最大值能到达 \(O(n^2)\) 级别,然而 \(k\) 只有 \(O(n)\),这启发我们在“压掉操作”的方向思考问题。考虑如果当前有连续的 \(len\) 个 1 想要向后填,那么此时的步数已经为 \(O(len^2)\),由于 \(k\) 只有 \(O(n)\),所以 \(len\) 只有 \(O(\sqrt k)\)。改一下状态,\(j\) 改为此时有多少个 1 想要往后填。在这个定义下 \(j\) 可以为负,此时代表有 \(j\) 个 0 要往后接纳要往前填的 1。
时间复杂度 \(O(nk\sqrt k)\)。
代码丢了。
P8360 [SNOI2022] 军队
有 \(n\) 个点,每个点有权值 \(a_i\) 和颜色 \(c_i(1\le c_i\le C)\),有 \(q\) 次操作:将 \([l,r]\) 内颜色为 \(x\) 的所有点的颜色改成 \(y\);将 \([l,r]\) 内颜色为 \(x\) 的所有点的点权加 \(y\);查询 \([l,r]\) 点权和。
\(n,q,C\le 2.5\times10^5,6\text{s},1\text{GB}\)
分析
这种问题一看就不大能 polylog,考虑分块,散块操作显然,整块一操作可以通过对颜色建点(注意一个颜色可能被先后多次建点),然后用并查集实现。操作二可以在并查集的基础上在每个点维护一个 tag 和 siz 实现。操作三直接在进行操作二时动态处理块内和即可。考虑散块重构,一个点最终的加和是它的所有祖先的 tag 之和。为了处理出这个东西,一种好写的做法是发现父亲编号大于儿子,然后倒着处理,这样就不用递归了。最终的颜色可以通过记录每个点代表的颜色 col 来实现。复杂度单根号。
但此时空间复杂度也是单根号的,实现不精细很可能被创飞,考虑到原题允许离线,所以我们离线下来后对每个块单独做就行了,这样只需要存这个块的信息,空间复杂度降为线性。
P3268 [JLOI2016] 圆的异或并
有 \(n\) 个圆,保证要么包含要么不交。求被奇数个圆覆盖的面积除以圆周率的结果。\(n\le 2\times10^5\)
分析
考虑对圆建一棵树,那么在奇数深度上的面积为正贡献,偶数深度上的面积为负贡献。考虑求圆的深度,扫描线后将整圆分成上半圆和下半圆,考虑在这条线上该圆上方的第一个半圆,如果这是一个下半圆,那么该圆和下半圆所属圆有相同的父亲;如果是上半圆,那么上半圆所属圆是该圆的父亲。考虑用 set 维护前驱后继,半圆的权值即为半圆与扫描线的交点 y 坐标。由于圆两两在圆上无交,所以无论扫描线扫到那权值的偏序关系不会改变。但是需要注意的是上下半圆的交点是重合的,可能会引起不必要的麻烦,所以选择将加入时间延后,删除时间提前。复杂度单 log。
P7515 [省选联考 2021 A 卷] 矩阵游戏
有一个 \(n\times m\) 的矩阵 \(a\),另有一个 \((n-1)\times(m-1)\) 的矩阵 \(b\),满足 \(b_{i,j}=a_{i,j}+a_{i+1,j}+a_{i,j+1}+a_{i+1,j+1}\)。
给定最终的 \(b\),要求构造一个合法的 \(a\) 满足 \(0\le a_{i,j}\le 10^6\),需要判断解的存在性。
\(n,m\le 300\)
分析
不妨让第 \(n\) 行和第 \(m\) 列都为 0,那么此时的 \(a_{i,j}\) 可以唯一确定。然后发现对一行/一列交替加某个定值,\(b\) 不会改变。不妨设第 \(i\) 行交替加 \(r_i\),第 \(j\) 列交替加 \(c_i\)。那么矩阵会变成这个样子:
+r1+c1 -r1+c2 +r1+c3 -r1+c4 ...
+r2-c1 -r2-c2 +r2-c3 -r2-c4 ...
+r3+c1 -r3+c2 +r3+c3 -r3+c4 ...
+r4-c1 -r4-c2 +r4-c3 -r4-c4 ...
...
写成约束的形式就是 \(0\le r_i+c_j\le 10^6\) 及 \(0\le r_i-c_j\le 10^6\) 等形式。后者可以写成差分约束的形式,但前者不能。考虑变换一下 \(r_i,c_j\),令第奇数行的 \(r_i\) 和第偶数列的 \(c_j\) 为它们的相反数,那么对于 \(r,c\) 同号的点有一个取了反,异号的点有两个或零个取了反,所有的限制都是差分形式,跑差分约束即可,最后别忘了把取反后的那些 \(r_i,c_j\) 取反回来。
\(n+m\) 个变量,\(2nm\) 个限制,所以复杂度三次方。
P10785 NOI2024 集合
给定两个长度为 \(n\) 的集合序列 \(a,b\),其中集合都是大小为 3、值域为 \([1,m]\) 的不可重集。定义两个集合序列等价当且仅当存在一个 \(m\) 阶排列 \(p\) 使得将第一个序列的所有集合的元素 \(x\) 都变成 \(p_x\) 后与第二个序列完全相等。\(q\) 次查询 \(a,b\) 的子区间 \([l,r]\) 是否等价。
\(n\le 2\times10^5,m\le 6\times10^5,q\le 10^6\)
分析
都排列置换相等了,自然考虑两个序列的所有数值的某一信息组成的可重集是否相等,由此我们得出一个结论:两个序列等价当且仅当 所有数出现的下标构成的集合 构成的集合相等。充分性和必要性都不难证。而这个东西考虑设计一个哈希函数来判断等价,内部的哈希函数随便乱造一个好维护的就行,外部的哈希函数最好别选位运算,我选的是内部异或(给每个下标赋一个随机权值然后异或起来,当然也可以构造多项式函数等)外部加法,模数自然溢出。
考虑查询。不难发现一个区间合法它的子区间合法,所以这东西有单调性,可以双指针,对于每个左端点只需要维护最大的合法右端点即可,复杂度线性。
P10786 NOI2024 百万富翁
交互题,给定长度为 \(n\) 的权值互不相同的序列,你需要找到其中的最大值的下标。你可以发送若干次请求,每次请求包括若干次询问 \((x,y)\),交互库会返回权值较大的那一个的下标。
\(n=10^6\),设 \(t\) 表示请求次数,\(s\) 表示询问总次数,满分要求 \(t\le 8,s\le 1099944\),有份要求 \(t\le 20,s\le 2\times10^6\)。
分析
考虑到我们只能通过询问完全图知道一个集合的最大值,而 \(t\) 又如此小,我们必须精细的规划每一层每一块的大小。根据不等式知识,总长、块数一定时,要想询问次数最小,最优解是让块长尽可能平均。所以我们设 \(f_{i,j}\) 表示用了 \(i\) 轮剩余 \(j\) 个数字的最小次数,转移枚举块数转移,复杂度 \(O(tn^2)\)。然而要跑出答案肯定一时半会跑不完,打几个范围千和万左右的数据可以发现,最优解的前四项块长都是 2,所以我们考虑钦定前四项块长为 2,再做上面的 DP,复杂度能除掉一个 \(512\),跑个几秒就能跑出最优解了。
一种合法的最优解:
1099944
500000 250000 125000 62500 20832 3472 183 1
QOJ11548/Gym105666D
给定 \(n\times n\) 坐标系上的 \(n\) 个点,每个点有类型 LR/UD,保证每行每列至多一个点。现在要给所有 UD 点从该点出发引一条向上或下指的射线,LR 点从该点出发引一条向左或右指的射线,求所有射线不相交的方案数,模数 \(10^9+7\)。
题解:发现如果所有 LR 确定了,UD 的贡献也确定了,反之同理。按列处理,分为两种情况讨论:
LLLLRRRR型,即存在一个分界点 \(i\),使得前 \(i\) 列的LR点左指,后面的列的LR点右指。枚举分界点,每个UD点的贡献可以 \(O(n)\) 计算。LLLLRLRRR型,即存在一个点 \(i\),使得 \(i\) 列上的点往左指,\(i\) 前面的第一个LR点向右指。为了不算重,枚举并钦定 \(i\) 是第一个满足这个条件的点。此时所有UD点的方向可以确定,根据UD点的方向可以推出LR的贡献,注意为了满足钦定条件 \(i\) 前面的点的方案数要特殊照顾一下(不是直接的 \(2^{cnt}\))。
总复杂度 \(O(n^2)\)。
CF2096F Wonderful Impostors
如果一个区间是 0 区间,那么就相当于区间内钦定填 0,而如果一个区间是 1 区间,那么如果该区间被 0 区间的并所包含,那么就不合法了。考虑维护线段树,0 区间的话就区间加 1,1 区间的话就查询区间最小值是否为 0。
首先不难发现固定 \(l\),合法性关于 \(r\) 具有单调性,所以可以考虑双指针。考虑加入区间,如果加入 1 区间,那么查一下区间最小值就行;如果加入了 0 区间,现在区间内全都不为 0 了,考虑找到两边第一个为 0 的地方,获得一个极长没有 0 的区间,然后查一下有没有 1 区间被其完全包含即可,这个还是可以线段树+底层 set/可删堆 维护每个右端点的最大左端点,然后查一下区间最大值是否小于极长区间的左端点即可。删除直接删就行,对当前局面合法性没有任何影响(原区间都合法删掉开头必然合法),复杂度单 log。
CF2127F Hamed and AghaBalaSar
阅读伪代码可以发现一个序列的权值等于序列所有最大值的和 - 所有最大值后一位的值的和 - 第一位的值。考虑拆贡献,先求第一部分,枚举最大值,分成 不在最后一位的最大值 和 在最后一位的最大值 两种情况讨论,如果设 \(f(n,m,k)\) 表示长度为 \(n\) 的序列,\(\sum a_i=m,0\le a_i\le k\) 的方案数,则两种情况方案数分别为 \((n-1)f(n-2,m-2k,k),f(n-1,m-2k,k)\)。然后考虑第三部分,发现如果接着枚举这一位的数复杂度就炸了,注意到如果设 \(g(n,m,k,p)\) 表示在 \(f(n,m,k)\) 的条件下 \(a_p\) 的和,则对于所有 \(p\),\(g(n,m,k,p)\) 都相等,因为你交换两个位置仍然满足条件,那么对于第一位的值之和,可以用所有位的值之和除掉序列长度得到,答案即为 \(\frac{(m-k)f(n-1,m-k,k)}{n-1}\),第二部分的贡献也是同理的,由于相当于是对所有位都求和一遍,所以不需要除以序列长度了,答案是 \((m-2k)f(n-2,m-2k,k)\),由于第 \(n-1\) 个位置的下一个是 \(n\),所以这部分贡献还要在算一次。
现在要对每个 \(k\) 求 \(O(1)\) 次 \(f(n,m,k)\),求单个 \(f\) 可以考虑容斥,钦定若干个位置 \(\ge k+1\),然后剩余部分的贡献就是插板法,由于钦定的数量大于 \(\frac{m}{k}\) 就没有贡献了,所以复杂度 \(O(\frac{m}{k})\),故总复杂度是调和级数。
HTCSP-S2025 C 阳光收集
这下真菜完了。
考虑会算重当且仅当删除一个字符后剩下的相等,于是我们钦定每次只能选连通块的开头删掉。你要是往记录连通块数量方向上想连个多项式复杂度做法都没有,我们可以考虑记录每个元素被删除的时间,那么需要满足其之前第一个删除时间大于它的颜色和其不同(这显然是充要的)。维护这个东西可以区间 dp 记录 \(f_{l,r}\) 表示填 \([l,r]\) 的方案数,且 \([l,r]\) 内的删除时间小于 \(l-1\)。转移考虑枚举最大值的位置,合并是一个组合数的贡献。复杂度 \(O(n^3)\)。
P4383 [八省联考 2018] 林克卡特树
发现是恰好选 \(k\) 个的类型,打个表发现有凸性(也可以费用流证),套个 wqs 二分后相当于截掉若干边使得截边的代价为惩罚值,然后在每个连通块内选出一条直径。直接设 \(f_{i,0/1/2}\) 表示以 \(i\) 为顶点的子树内,\(i\) 所属的连通块尚未选边/正在选边/选边完成的最大价值。转移并不困难,时间复杂度 \(O(n\log V)\)。

浙公网安备 33010602011771号