杂题乱做 - 2100+
- 写在前面
- CF1981D 构造,数学,欧拉路径 2400
- CF1988E 笛卡尔树 2300
- CF2006C 数学,双指针 2300
- CF1528C 树,数据结构 2300
- CF2008H 枚举,二分,调和级数 2100
- CF2009G1/G2 数据结构 2200
- [AGC016D] XOR Replace 结论,异或,图论
- CF1993E 结论,异或,状压 DP 2700
- CF2000G 二分答案,最短路 2100
- CF2000H 线段树 2200
- CF1975E 结论,树 2100
- CF1968G1/G2 Z 函数,调和级数,贪心 2100
- CF1967C 树状数组,计数 2300
- CF1949G 贪心,图论,构造 2300
- CF1996G 线段树,异或哈希 2200
- P1484 反悔贪心 提高+/省选−
- CF1949F 贪心、排序、树 2200
- CF1300E 贪心 or 凸包 2100
- T515404 线段树、树上启发式合并 about2300+
- P6046 概率期望,DP 提高+/省选−
- CF1680D 枚举,贪心 2400
- CF1687C 枚举,贪心,结论 2500
- CF540E 数据结构,实现 2100
- AT_abc221_g 曼哈顿距离转切比雪夫距离,bitset 优化背包,构造 NOI/NOI+/CTSC
- CF1073E 数位 DP 2300
- CF450E 构造,数论 2100
- CF832C 二分答案,枚举 2100
- 写在最后
写在前面
我是飞物。
CF1981D 构造,数学,欧拉路径 2400
妈的好诡异的题场上拿到这题我都不知道我要干啥呃呃
考虑到每个合数均为若干质数的乘积,则若构造方案中有合数,可以将合数替换为质数从而减少使用的权值的种类数,于是仅需考虑使用质数构造,则此时并不需要考虑具体使用了哪些质数,且此时 \(a_{i}\times a_{i + 1} = a_{j}\times a_{j + 1}\) 的充要条件即为无序对 \((a_{i}, a_{i + 1}) = (a_{j}, a_{j + 1})\)。该限制和无重边很像。则若已知需要 \(m\) 种质数进行构造,问题等价于在一张 \(m\) 个点的带自环的完全图中,找到一条边数为 \(n - 1\) 的欧拉路径。使用 Hierholzer 算法即可 \(O(m^2)\) 地解决。
于是考虑至少需要多少种质数才可构造出 \(n-1\) 条边的欧拉路径。由于自环的贡献显然可以全部得到,于是仅需考虑非自环边的影响。若 \(m\) 为奇数则所有点度数均为偶数,显然最长欧拉路径可以包括所有非自环边,数量为 \(\frac{m(m - 1)}{2}\);若 \(m\) 为偶数则所有点度数均为奇数,则需要屏蔽一些边使得该图存在欧拉路径,使非零度点是连通的,且有不多于 2 个奇度点。发现删去一条边至多使奇度数点减 2,则至少需要删除 \(\frac{m}{2} - 1\) 条边,且使这些边无交点。则钦定删除 \((2, 3), (4, 5), \cdots, (m - 2), (m - 1)\) 即可,则最长欧拉路径包括的非自环边数为 \(\frac{m(m - 1)}{2} - \frac{m}{2} + 1\)。
发现上面的式子关于 \(m\) 是单调的,则可以二分求得至少需要多少种质数。发现 \(n=10^6\) 时 \(m\approx 1100\),显然不会超过上界 \(3\times 10^5\)。
另外先尝试了不显式地建图然而比用 vector
显式建图怎么慢十倍啊我草
CF1988E 笛卡尔树 2300
学习了!
答案即为对于每个权值求有多少个区间以其为最小值,经典单调栈/笛卡尔树问题,建笛卡尔树后,用节点的权值和子树大小计算求和即可。
考虑扔到笛卡尔树上考虑删数后的询问。手玩下被影响的区间位置,发现删去一个节点后,该节点子树外的贡献无影响,对于该子树受影响的仅有其左儿子的右链,和右儿子的左链受到影响,且影响为将这两条按深度权值递减的链,上面的节点按照权值大小归并为一条新的链。
发现对于每个节点均枚举左儿子的右链和右儿子的左链,会且仅会枚举每个点 \(O(1)\) 级别,则考虑 dfs 整棵笛卡尔树并每次直接暴力枚举求链合并后答案的增量即可,具体贡献形式详见代码。总时间复杂度 \(O(n)\) 级别。
CF2006C 数学,双指针 2300
首先连续相等的长度为 \(l\) 的区间贡献为 \(\frac{l(l + 1)}{2}\),先统计这部分然后将原数列连续相等的区间缩成一个数。
考虑对于一个集合,对于每次操作的两个数 \(x, y\) 一定是奇偶性相同的,且 \(\frac{x+y}{2}\) 不在集合中。发现无法进行操作时集合相邻的数的差分均为奇数(相邻的数无法操作),且一定构成等差数列(不相邻的数也无法操作),若公差为 1 说明集合是有贡献的。手玩下发现此时的公差即原集合的差分的 \(\gcd\) 除去所有因子 2 的值,则若集合合法,差分的 \(\gcd\) 一定是 2 的幂。
由辗转相减,可知差分的 \(\gcd\) 与集合元素的顺序实际是无关的,则对于一个区间 \([l, r]\) 是否有贡献仅需判断 \(\gcd(a_l, \cdots, a_r)\) 是否为 2 的幂即可,又发现此时若区间扩大 \(\gcd\) 显然只会单调递减且一定也为 2 的幂,于是可以双指针+ST表求区间 \(\gcd\) 统计贡献。
总时间复杂度 \(O(n\log^2 n)\) 级别。
CF1528C 树,数据结构 2300
发现对第一棵树选点的限制是必须在一条从根到叶的链上,第二棵树选点限制是选的点在构成的虚树上均为叶节点。
考虑每次在第一棵树上多选一个点 \(u\),对第二棵树上选的点的虚树的影响:
- 若 \(u\) 是已选的点的祖先,显然用它替换它的祖先不会更优,贡献为 0。
- 若 \(u\) 在已选的点的子树中,显然用它替换它的祖先不会更劣,贡献为 0。
- 否则可直接将 \(u\) 加入,贡献为 1。
发现我们可以唯一确定选点的策略,于是考虑直接 dfs 枚举所有第一棵树上从根到叶的路径,并在此过程中动态维护路径上的点的选择情况即可。问题转化为如何支持在第二棵树上动态增/删点,查询新增的点是否与已经选择的点有祖先关系。
考虑对第二棵树预处理 dfs 序与每棵子树对应区间,有祖先关系说明新增的区间与之前的区间有交,使用 set 即可维护;当然也可以上线段树维护,仅需支持子树加/子树查询即可。复杂度均为 \(O(\log n)\) 级别。
呃呃然而我当场写了个 2log 的傻逼做法:https://codeforces.com/contest/1528/submission/279307913
CF2008H 枚举,二分,调和级数 2100
显然对于任意的 \(x\),最优的操作是将每个数调整为 \(a_i\bmod x\)。
考虑二分答案 \(\operatorname{mid}\),问题变为检查是否 \(a_i\bmod x \le \operatorname{mid}\) 的 \(a_i\) 的数量不小于 \(\left\lfloor\frac{n}{2}\right\rfloor + 1\),即检查权值区间 \([0, \operatorname{mid}], [x, x + \operatorname{mid}], [2x, 2x + \operatorname{mid}], \cdots\) 中数的个数。
发现枚举区间的数量是个调和级数的形式,于是考虑枚举所有 \(x\in [1, n]\) 按上述算法二分预处理即可。
总时间复杂度 \(O(n\log n\ln n + q)\) 级别。
CF2009G1/G2 数据结构 2200
首先套路地令 \(a_i:= a_i - i\),则令区间变为公差为 1 的等差数列即令区间相等。
G1:显然对于一个长度为 \(k\) 的区间应该调整成其中的众数,于是直接枚举所有长度为 \(k\) 的区间,记录区间内权值出现次数预处理即可。
G2:考虑 G1 中预处理了所以长度为 \(k\) 的区间的答案 \(g_1\sim g_{r-l+1}\),则对于询问 \([l, r](r-l+1 >k)\),结果即为 \(\min\limits_{l\le i\le r-k+1} g_{i}\)。
这东西显然有有单调性,于是考虑将询问按左端点降序排序,然后枚举询问左端点,在此过程中维护一个单调栈储存从当前左端点向右枚举时的前缀最小值,查询即相当于做一个从栈顶到栈底的前缀和。
因为要入栈出栈直接做前缀和很难做,但是可以套路地转换成后缀和之差就很好做了,则仅需在单调栈上二分找到端点即可。
G3:考虑把 G2 的维护过程扔到线段树上进行,然后套路地可持久化即可,查询等价于在历史版本连续的线段树上做同一个点的单点查询之和。实际上有简单的更牛逼的做法,考虑每个前缀最小值的贡献即可。
妈的 G3 怎么 2700 啊这还是 div4?感觉有点呃呃就没写。
[AGC016D] XOR Replace 结论,异或,图论
好玩题。
发现对 \(a_i\) 进行一次操作相当于令 \(a_i:=\oplus_{1\le i\le n} a_i\),再对 \(j\) 进行一次操作相当于令 \(a_j:= a_i\)。
则题意等价于有一个长度为 \(n + 1\) 的数列 \(a\),\(a_{n + 1} = \oplus_{1\le i\le n} a_i\),每次可以交换 \(a_i\) 与 \(a_{n + 1}\),求最小交换次数令 \(\forall 1\le i\le n, a_i = b_i\)。
则判断有解仅需判断 \(a_1\sim a_{n + 1}\) 中每种权值出现次数大于 \(b_1\sim b_n\) 中对应权值的出现次数即可。
然后考虑将一种权值的位置缩成一个点,考虑一类排列交换元素问题的套路,若初始时 \(a_i\not= b_i\) 则应在交换过程中用权值 \(b_i\) 替换 \(a_i\),于是考虑转化为图论问题,令 \(b_i\) 对应节点与 \(a_i\) 对应节点连边,
答案即连边数量(每个位置都需要操作)减去大于 1 的连通块的数量(可以节省的操作数量)。
CF1993E 结论,异或,状压 DP 2700
先考虑一维的情况。
若只有一维,每次操作的结果和 [AGC016D] XOR Replace 是一样的。对 \(a_i\) 进行一次操作相当于令 \(a_i:=\oplus_{1\le i\le n} a_i\),再对 \(j\) 进行一次操作相当于令 \(a_j:= a_i\)。
则题意等价于有一个长度为 \(n + 1\) 的数列 \(a\),\(a_{n + 1} = \oplus_{1\le i\le n} a_i\),可以任意交换 \(a_i\) 与 \(a_{n + 1}\),对于 \(a_1\sim a_n\) 求相邻两项差的绝对值之和的最小值。
发现数据范围很小,且贡献仅与相邻元素有关,考虑状压 DP 构造数列,记 \(f_{s, i}\) 表示当前填入的数列元素集合为 \(s\),填入的最后一个数是 \(a_i\) 时美丽值的最小值。初始化 \(f_{s, i} = \infin, f_{\{i\}, i} = 0\),则有显然的转移:
记全集为 \(S\),答案即为:
总时间复杂度 \(O(n^2 2^n)\) 级别。
扩展到两维,发现若先进行一次行操作再进行一次列操作,等价于将交点位置修改为整个矩阵的异或和。于是考虑扩展上述做法,题意等价于有一个大小为 \((n + 1)\times (m + 1)\) 的矩阵,第 \(n+1\) 行为各列的异或和,第 \(m+1\) 列为各行的异或和(\((n + 1, m + 1)\) 即整个矩阵异或和),每次操作可以交换两行/两列,求左上角 \(n\times m\) 矩阵的美丽值的最小值。
考虑预处理任意两行/两列相邻时的贡献。发现两维的贡献是独立的,不同维的交换并不影响另一维的贡献。发现若枚举了哪一行被放在了 \(n+1\) 行上,则对列的贡献的计算就可以直接套用一维的做法了。于是考虑转移时处理 \(\operatorname{sum}(i, j)\) 表示将第 \(i\) 行第 \(j\) 列时的最小美丽值,取最小值即可。
在一维做法的基础上仅需再多枚举一维即可,总时间复杂度 \(O(n^2m 2^n + nm^2 2^m) \approx O(n^3 2^n)\) 级别。
CF2000G 二分答案,最短路 2100
显然可以二分答案枚举最早何时出发。
发现经过的路径可以分为三个阶段:\(t_1\) 之前可以坐车可以步行,\(t_1\sim t_2\) 只能步行,\(t_2\) 之后坐车最优,于是考虑记 \(\operatorname{dis}_{u, i}(0\le i\le 2)\) 表示到达节点 \(u\),且当前位于阶段 \(0\sim 2\) 时的最短路径长度,显然可以跑 Dijkstra 转移,根据当前状态枚举到达邻接点的下一状态即可。
实现时并不需要显示地记录上述三种状态,可以直接根据当前最短路长度判断所处状态。
CF2000H 线段树 2200
比较裸。
发现至多只有 \(n\) 段有贡献的空区间,于是考虑记录每段空区间的开头和长度,插入和删除相当于分裂或者合并相邻的区间,可以用 set 很简单的维护。然后对上述空区间用线段树维护区间最大长度,线段树二分查询即可。
以为直接用 set 就能做完呃呃发现还是要用线段树太唐。
CF1975E 结论,树 2100
实际结论特判题,并非大力数据结构!
所有黑点构成且仅构成一条连续的链,当且仅当:
- 没有黑点有 2 个以上的黑点作为子节点;
- 至多只有一个黑点的父节点是白色的;
- 至多只有一个黑点有 2 个黑点作为子节点;
- 若有黑点有 2 个黑点作为子节点,则其父节点一定是白色的。
显然每次修改 \(x\) 仅会影响:
- \(\operatorname{fa}_x\) 的黑色子节点的数量;
- 父节点为黑色的节点的数量;
考虑维护每个节点的子节点中有多少点是黑色的,与子节点中有 0/1/2/3+ 个黑点的黑点的数量。则每次修改 \(x\) 可直接修改 \(\operatorname{fa}_x\) 的信息,新增 \(x\) 的信息的贡献;且每次修改对父节点为黑色的节点的数量的增量,即为 \(x\) 的子节点中有多少点是黑色的,再加上 \(x\) 的贡献。
则每次修改都可以 \(O(1)\) 地完成,查询则大力判断是否合法即可。
详见代码:https://codeforces.com/contest/1975/submission/280553428。
CF1968G1/G2 Z 函数,调和级数,贪心 2100
我去 div3 居然有 Z 函数的题呃呃,不过倒是没卡哈希+二分所以暂且认为 div3 有这题不算超纲。
由 \(\operatorname{lcp}\) 的性质可知答案显然有单调性,即一定有 \(f_{i} \ge f_{j}(j > i)\)。
考虑对于某个答案 \(\operatorname{len}\) 对于询问 \(k\) 是否合法,发现问题实际上即选出一些位置 \(p_1, p_2, \cdots, p_k\),钦定 \(p_1 = 1\),\(\operatorname{lcp}(s, s[p_i:n])\ge \operatorname{len}\),且 \(p_i \ge p_{i - 1} + \operatorname{len}\)。
发现 \(\operatorname{lcp}(s, s[p_i:n])\) 即 Z 函数的定义,于是先求 Z 函数然后考虑按 Z 函数倒序枚举所有位置(即倒序枚举答案 \(\operatorname{len}\) 的长度),并检查选择上述所有位置,在满足 \(p_i \ge p_{i - 1} + \operatorname{len}\) 的限制下至多能选多少。设可以选择 \(c\) 个,则一定有 \(f_c \ge \operatorname{len}\)。
选位置一定是贪心地尽可能选最小的,且又发现枚举到 \(\operatorname{len}\) 时至多仅会选择 \(O\left(\frac{n}{\operatorname{len}}\right)\) 个位置,它们的数量总和是个调和级数的形式,于是在枚举 \(\operatorname{len}\) 时用 set 维护所有可选的位置,然后在 set 上找最优的位置大力贪心即可。
求得的 \(f\) 取后缀最大值即为答案。
总时间复杂度 \(O(n\ln n\log n)\) 级别。
CF1967C 树状数组,计数 2300
非常好玩的题,考察对树状数组本质形态的理解。
树状数组本质上是二进制优化的前缀和,由题目给定的式子可以看出来,每个树状数组的位置 \(s_k\) 实际上是以 \(k\) 为右端点的,长度为 \(\operatorname{lowbit}(k)\) 的区间的和。
而本题对给定数组做了 \(k\) 次建立树状数组的操作,实际上即对所有树状数组区间做了 \(k\) 维二进制优化的前缀和。众所周知做高维前缀和时,每个位置对之后的位置的贡献的系数由下表所示,由组合意义易知位于 \((x, y)\) 的系数的值即 \({{x + y}\choose {y}}\):
\(a\) | 1 | 1 | 1 | 1 |
---|---|---|---|---|
\(f^1\) | 1 | 2 | 3 | 4 |
\(f^2\) | 1 | 3 | 6 | 10 |
\(f^3\) | 1 | 4 | 10 | 20 |
\(f^4\) | 1 | 5 | 15 | 35 |
记需要还原出来的数列为 \(a\),考虑对于每个位置 \(i\) 会对哪些位置 \(p\) 的高维前缀和 \(f^k(p)\) 有贡献。由建树状数组的过程可知,\(p\) 可以通过树状数组插入操作进行枚举,易知此类位置只有 \(O(\log_2 n)\) 数量级。
根据高维前缀和的式子,手玩下系数矩阵,发现若位置 \(p\) 是在树状数组插入操作时第 \(j(j\ge 0)\) 个被枚举到的位置,则 \(a_i\) 对 \(f^k(p)\) 的贡献的系数即为:
于是考虑顺序枚举所有位置并进行还原,还原第 \(i\) 个位置的值 \(a_i\) 后,考虑枚举它有贡献的位置并减去 \(a_i\) 的贡献即可。
总时间复杂度 \(O(n\log n)\) 级别,代码非常好写!
哎呦我草太优美啦树状数组!
CF1949G 贪心,图论,构造 2300
妈的这题 2300?感觉真水吧呃呃
保证每栋楼只能到一次,考虑将所有楼栋按照需求的教授和当前教授分为 6 类点:
类型 | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
需求 | \ | \ | M | C | M | C |
教授 | C | M | C | M | \ | \ |
保证每栋楼仅经过一次,则发现骆驼祥子的移动路线一定是如下形式的:
一个显然的想法是考虑按照上述路线建图,直接大力枚举 0/1 类型的点作为起点,并大力在图上 dfs,经过尽可能多的 2/3 类型的点,最后尽可能在 4/5 类型的点结束路线。则每次移动一定会使当前到达的点满足要求,且按照上述方案贪心一定可以覆盖到最多的点。则直接贪心地构造路线即可。
总时间复杂度 \(O(n^2)\) 级别。
CF1996G 线段树,异或哈希 2200
线段树解法非常无脑。发现只要确定一条边被删掉即可断环成链,则其他所有边是否被删即可唯一确定。在此过程中考虑使用线段树标记哪些区间是一定不能被删的,则最多可以保留的边数即全局的非 0 个数。
于是考虑扫描线枚举删除的是哪条边,则对于路径 \((a, b)\),若边在 \([a, b]\) 上则标记 \([1, a), (b, n]\) 为一定不能删,否则标记 \([a, b]\);在更换删除的边时仅需支持区间 \(\plusmn 1\),查询全局的非 0 个数即可,非常容易维护。
不过还是太无脑太难写了!另有一种极其优美好写的异或哈希做法。
同样考虑确定一条边被删掉,可唯一确定其他所有边是否被删,这说明在一种删边方案中,被删的边被路径覆盖的情况都是一致的。于是一个想法是考虑维护每条边被路径覆盖的情况。于是套路地考虑使用异或哈希进行维护。
考虑将原图看做一个正 \(n\) 边形,则路径 \((a, b)\) 可看做将正 \(n\) 边形切成两半的对角线,两半的路径被覆盖情况是对立的,于是仅需选择其中一半的所有路径,令他们均异或上同一个随机数,从而与另一半对立即可。因为是一个区间异或的形式,套路地转化成异或差分即可 \(O(1)\) 地标记每一条路径影响的所有边。
使用 map
维护所有哈希值的出现次数,由上述分析可知,查询最多的哈希值的出现次数,即为最多可删去多少边。
超级好写!见:https://codeforces.com/contest/1996/submission/280919855
类似的题为:CF1977D。
P1484 反悔贪心 提高+/省选−
好玩反悔贪心。
显然答案中不会有负数,且发现对于连续的三个正数 \(a_{i-1}, a_i, a_{i + 1}\),选择情况仅有两种:仅选中间的 \(a_i\),或同时选两边的 \(a_{i - 1} + a_{i + 1}\)。
考虑反悔贪心,如果第一步选择了中间的 \(a_i\),发现可以先删去 \(a_{i - 1}, a_{i + 1}\),然后构造一个新位置,该位置的贡献为 \(a_{i - 1} + a_{i + 1 } - a_{i}\),若选择了新位置则证明进行了反悔。
进一步地,考虑对于选择的连续的一段隔一个选一个的数,选择情况仅有两种:隔一个选一个,或对称地选一个隔一个。发现同样可以使用类似的方法构造反悔的贡献,于是上述做法可以进行拓展。
使用使用双向链表维护删除后的前驱后驱,优先队列维护可以选择的区间与贡献实现。总时间复杂度 \(O((n + k)\log n)\) 级别。
CF1949F 贪心、排序、树 2200
问题等价于给定若干集合,选出任意两个集合,使得他们满足有交,且不存在包含关系。
考虑按照集合大小降序枚举,并按照集合包含关系动态建树,令每个集合连向最小的包含它的集合,则有包含关系的一定不合法;考虑在上述模拟建树过程中,维护每个权值最晚出现在哪个集合中,然后枚举集合内所有元素检查其父节点:
- 若集合内元素最晚出现集合均相同,则父节点唯一;
- 否则,由树形结构可知,当前集合与集合内元素最晚出现集合中任意一个均为合法解。
排序后即可线性实现即可,总时间复杂度 \(O(n\log n + m)\) 级别。
CF1300E 贪心 or 凸包 2100
考虑求前缀和 \(\operatorname{sum}_i\),看做二维平面上的 \(n\) 个点 \((i, \operatorname{sum}_i)\),相邻点之间连线。
则一次操作可看做选择两个点直接连线,并删去它们之间的所有线段,它们之间所有位置的贡献即变为线段的中点。发现在这种定义下,此时为了最小化字典序,等价于求原二维数点的下凸包,下凸包对应的操作方案即最优的答案。
实际实现时并不需要真的求凸包(虽然求凸包也能过),仅需考虑顺序枚举所有位置 \(i\),并考虑是否将 \(i\) 与之前一段合并即可,等价于上述求下凸包并删去凸包内的线段。考虑使用单调栈维护当前所有段的端点与均值,每次加入仅包含 \(i\) 的一段,然后不断检查能否将栈顶两段合并使得均值更小。若可以则不断弹栈。
最终栈中所有段依次输出即为最终答案,可以保证至多仅有 \(n\) 段,且入栈出栈与合并至多进行 \(O(n)\) 次,总时间复杂度 \(O(n)\) 级别。
T515404 线段树、树上启发式合并 about2300+
江队倾情改编 CSP T5。
发现操作相当于进行集合的分裂,原数列中每个数在同一时刻只能存在于一个数列中,于是考虑反向操作进行,使用 set 维护每个数列内的权值,然后反向地进行启发式合并,每次合并后直接查询 size 即为答案。时间复杂度 \(O(m\log^2 n)\) 级别。
于是考虑如何求得初始状态——即原数列中每个数最终位于哪个数列中。发现对于同一个数列的分裂操作,时间靠前的优先级较高;对于同一个位置的操作,时间靠后的优先级较高;对于每个位置,求得的优先级最高的操作,即为最终所在的数列。
发现上述优先级关系,实际上构成一个树形结构(兄弟节点之间有优先级,父子节点之间有优先级),考虑离线操作,还原出原数列的区间,并模拟建树得到每个操作的优先级。然后使用线段树对区间打优先级的标记,维护每个节点的最大值即可。
总时间复杂度 \(O(m\log^2 n)\) 级别。
江队的 std 是 dsu on tree 单 \(\log\) 跑不过,但是我这个 set 启发式合并代码复杂度实在低太多所以还是赢赢赢嘻嘻
提交记录:https://www.luogu.com.cn/record/178454071。
P6046 概率期望,DP 提高+/省选−
我去数据范围这么小?感觉能随便乱搞啊
考虑枚举每一个容器,并枚举这个容器存活到第几轮并单独计算概率。
记容器 \(i\) 左边/右边第一个大于它的容器为 \(L_i, R_i\),则若某个容器若能存活到第 \(j\) 轮,说明 \([L_i, i]\) 和 \([i, R_i]\) 这两个区间内相邻的容器均没有被完全操作,从而使得容器 \(i\) 仅会与小于它的容器操作从而存活。
考虑记 \(C_1 = i - L_i, C_2 = R_i - i\),考虑反面求容器被干掉的概率,再考虑操作是否完全覆盖上述区间,则可得存活到第 \(j\) 轮的概率为:
则容器 \(i\) 的答案即为:
复杂度 \(O(n^2)\) 级别。
CF1680D 枚举,贪心 2400
显然有解当且仅当全局之和为 0。
考虑最大化有解时的答案,发现 \(O(n^2)\) 可过,考虑枚举修改后的哈基汪正负位置的极值出现的位置 \(p_1, p_2\),则答案即区间 \([p_1, p_2]\) 之和。问题等价于考虑如何在最大化极差的同时,平衡对区间 \([p_1, p_2]\) 内外的修改,使得区间内外之和恰好为原数列之和。
一个显然的贪心是考虑令区间 \([p_1, p_2]\) 内可修改位置均修改为 \(+k\) 或 \(-k\) 使得极差取到上界,但受外部可修改的数量限制,有可能无法取到该上界,但另一个显然的贪心是在区间内可修改位置均修改为 \(+k\) 时,记此时区间内之和为 \(s_1\) 为了平衡外部可修改位置应尽可能取负值,记外部可修改位置全部取 \(-k\) 时和为 \(s_2\),则此时极差的上界为 \(\min(|s_1|, |s_2|)\),且显然一定可以取到该上界。另一种修改的情况同理可解决。
复杂度 \(O(n^2)\) 级别。
CF1687C 枚举,贪心,结论 2500
考虑构造数组 \(c_i = a_i - b_i\),问题变为每次选择一段区间 \([l, r]\),满足 \(\sum_{l\le i\le r} c_i = 0\),使得区间全部清零,最终结果即为使得数组 \(c\) 全部清零。观察到上述区间和的形式,考虑套路地做个前缀和 \(s_i = s_{i - 1} + c_i\),问题变为每次选择 \(s_{l_i - 1} = s_{r_i}\),并将区间赋值为 \(s_{l_i - 1}\),最终结果仍为使得 \(s\) 全部清零。
发现每次对 \(s\) 赋值只能将区间修改为原数列中出现的数,为了使得 \(s\) 全部清零则应当仅考虑增加 0 的数量,则应当仅选择 \(s_{l_i - 1} = s_r = 0\) 的区间进行操作。又考虑到每个位置仅会被赋值 0 至多一次,每个位置仅会作为操作端点显然至多只会进行两次,于是考虑每次选择最靠左的 0,检查能否向右操作使得有非 0 位置被赋 0 即可。
使用堆维护所有 0 位置与非 0 位置即可,总时间复杂度 \(O((n + m)\log n)\) 级别。
CF540E 数据结构,实现 2100
很容易通过 map
维护所有被修改的位置最后的权值,很容易通过树状数组维护它们之间的逆序对数。
那么如何计算未被修改的位置,与被修改位置之间的逆序对的贡献呢?显然未被修改的位置之间不会产生贡献。发现未被修改的位置,被被修改的位置分成了 \(O(n)\) 段区间,区间内的权值连续,则显然若某个未被修改的位置,与某个被修改位置产生逆序对,则它所在的区间中其他数也一定会产生贡献。
考虑枚举所有被修改位置,以及上述 \(O(n)\) 段区间,将区间缩成一个位置,其权值为区间长度,表示一次会产生贡献的数量,则可以直接套用到上述树状数组求逆序对的过程中。
用一点 STL 会写的比较舒服。
AT_abc221_g 曼哈顿距离转切比雪夫距离,bitset 优化背包,构造 NOI/NOI+/CTSC
真的有黑题吗?虽然确实这个转化很牛逼但是存疑。
发现对于原操作,每次操作只会对某一维产生贡献,则需要同时考虑两维,比较麻烦。
一个套路是考虑曼哈顿距离转切比雪夫距离,终点变为 \(X = A - B, Y = A + B\),则四种操作变为:
发现所有的操作每一维都是 \(\plusmn d\),考虑将每一维都平移 \(\sum d\),则终点变为 \(X = A - B + \sum d, Y = A + B + \sum d\),进一步地操作变为:
发现此时对于一次操作,可以任意选择不产生贡献、仅对某一维产生贡献、对两维同时产生贡献,则此时可将两维看做独立的问题。
对于一维的子问题,问题等价于有 \(n\) 个物品,选择第 \(i\) 个物品产生 \(d\) 的贡献,要求构造选择方案使得贡献之和恰好为 \(X\) 或 \(Y\)。显然的 01 背包问题,考虑到 \(n\) 和坐标的值域不太大,考虑 bitset
优化即可。然后根据背包逆序还原操作方案即可。
CF1073E 数位 DP 2300
注意:数位 DP 记忆化的是根据当前确定的前缀状态,可以构造出的所有合法后缀的贡献之和。
套路数位 DP,设 \(f_{i, s}\) 表示构造了长度为 \(i\) 的前缀,其中各个数出现情况为 \(s\),可以构造出的合法的后缀的方案数,\(g_{i, s}\) 表示表示构造了长度为 \(i\) 的前缀,其中各个数出现情况为 \(s\),可以构造出的合法的后缀的贡献之和。
特别注意上述状态的含义!
预处理一下 10 的幂,然后套路地 dfs 枚举下一位转移即可。
CF450E 构造,数论 2100
上古 2500 现在也就 2100 水平。
套路地考虑枚举公因数并进行构造。一个显然的结论是仅需考虑公因数为质数的情况即可,且显然公因数越大能构造的数对越少,于是考虑降序枚举质数 \(p\) 作为公因数,再枚举其所有未被凑成数对的倍数。
发现当无倍数时,则该质数永远无法匹配;倍数个数为偶数时,此时将它们两两匹配一定不会更劣;当倍数个数为奇数时,考虑把一个倍数拿出来在之后再进行匹配,显然其中限制最弱的倍数为 \(2\times p\),于是将其取出并将其他倍数两两匹配。最后将被单独拿出的 2 的倍数尝试两两匹配即可。
类似埃氏筛实现即可,总时间复杂度 \(O(n\ln n)\)。
CF832C 二分答案,枚举 2100
同样上古 2500 现在也就 2100 水平。
题面好生草。
显然答案有单调性,考虑二分答案,并检查是否存在一个炸弹放置位置使得该时间合法。考虑枚举每一个人 \(i\) 并检查使之在规定时间内到达终点的合法的炸弹放置位置,显然能直接方程解出来一段以 \(x_i\) 为端点的区间。
存在某个位置放置炸弹使得同时有两个人分别能到达两边的终点即合法。
写在最后
我是……?