2024.03 做题笔记
- CF925E
转化一下题意:树上每个点有点权,每次操作对于一条某个点到根的链 \(+1\) 或 \(-1\),并切换这个点的颜色(黑/白),求每次操作后点权 \(>0\) 的白点个数。
考虑分块重构,每 \(B\) 个操作分一块,对于操作内的影响,把块内的关键点建出虚树。预处理出虚树上每条边对应的点的点权从小到大排序的情况。那么每次操作需要对一些虚树上的边进行修改,由于每次 \(+1\) 或 \(-1\),所以变为合法/不合法的边权个数是 \(\mathcal O(1)\) 的。而每次操作至多修改 \(\mathcal O(n/B)\) 条虚边,所以取 \(B=\mathcal O(\sqrt {n\log n})\) 复杂度最优,为 \(\mathcal O(n\sqrt{n\log n})\)(瓶颈是排序)。每次一个块搞定之后把当前的影响加到整体的影响上,这个过程是 \(\mathcal O(n)\) 的。
- P10063
直接根据质因子判完全平方太难了,考虑利用二次剩余的性质:如果设二次剩余为 \(1\),非二次剩余为 \(0\),那么乘起来得到的结果的二次剩余状态等于两个数的二次剩余状态的异或。
任取 \(S\) 个质数 \(p_1\dots p_S\),对于 \(a_i\),如果在 \(\bmod p_j\) 意义下是二次剩余,那么将 \(s_i\) 的二进制下第 \(j\) 位设为 \(1\),题目所求就是异或和为 \(0\) 的区间个数。
预处理即可,\(\mathcal O(n\log V+SP)\),取 \(S=60,P=3\times 10^6\) 即可通过。
- CF1929E
本质不同的边覆盖状态只有 \(\mathcal O(k)\) 种,预处理出来之后状压 dp,\(\mathcal O(nk+k2^k)\)。
- CF1929F
这个题除了第一步没有任何含金量。
把树拍扁成中序遍历,那么问题就变成一些位置未知,要填上 \([1,C]\) 中的正整数使得序列不降,随便插板乱算就行了。
- P9665
没有任何技术含量,就是纯硬核数据结构。
经典结论:一个点集的直径可以由两半直径四个点两两组合得到。
那么考虑对每种颜色建立动态开点线段树,维护每种颜色的直径。在颜色维度上建立线段树,每个区间维护两种信息:\([l,r]\) 内任意选的直径,\([l,r]\) 内不同色点对的直径。合并的时候第一种直接四个点六种组合即可,第二种可以从两半中继承第二种贡献,也可以从两边的任意直径中匹配一组。
直接做复杂度是 2log,考虑 \(\mathcal O(n\log n)-O(1)\) 欧拉序 LCA,优化到 1log,但是常数还是逆天的大,重度卡常题。
- P6097
子集卷积实际上做了这样一件事情:我们在 FWT 统计 \(i \operatorname{or} j=k\) 的同时,记录一下 popcount,并限制 \(popcount(i)+popcount(j)=popcount(k)\),这样需要做 \(\mathcal O(n)\) 次 FWT,合并是 \(\mathcal O(n^22^n)\),总复杂度 \(\mathcal O(n^22^n)\)。
- P6570
发现这个 sum 就是来骗人的,因为二进制位都不相交了,sum 不就是 or 吗,那么随便子集枚举 dp 就行了。
打这场比赛的时候还是太年轻了,这种题不会做也正常。
- P5445
首先维护能否联通可以通过线段树或者 ODT 维护连续段实现,那么问题变为矩形修改,单点查询历史和。
看起来不好做,但是我们可以在联通的时刻 \(-t_1\),断开的时刻 \(+t_2\),这样你就发现这段时间的贡献恰好是正确的 \(t_2-t_1\)。那么直接转单点修改矩形求和,用树套树做即可。
- P10040
疑似有点逆天。
考虑 bitset,每次 \(k\) 位为一块的直接平移出答案,复杂度 \(\mathcal O(\frac{n^2\log n}{w})\)。
一个可以通过的方法:较小的 \(k\) 跑暴力,较大的 \(k\) 做 bitset,取 \(k=\mathcal O(\sqrt n)\),可以通过。
正经做法:考虑二进制分块,对于 \([2^i,2^{i+1}-1]\) 这段区间,全部用大小为 \(2^{i+1}-1\) 的 bitset 解决,那么复杂度就是正确的 \(\mathcal O(\frac{n^2}{w})\) 了。
- P10044
【模板】广义串并联图。
第一次独立想 + 写广义串并联图,还算比较成功。
考虑去除重边,自环,删除所有入度或出度为 \(0\) 的点,缩合入度出度同时为 \(1\) 的点,这样边数点数都变成了 \(\mathcal O(m-n)\),直接暴力最小环即可。
最小环:从每个点开始跑最短路。(有个人想了 1min 最小环咋做,是不是有点太糖了)
- P10045
将每个数拆成 \((2a_i+1)\) 的形式,考虑形式幂级数,求 \(\prod (2a_ix+1)\) 的各项系数之和。发现 \(\ge 20\) 次的在 \(\bmod 2^{20}\) 意义下都是 \(0\),所以只需要求 \([0,19]\) 次项系数。
考虑线段树,每次 \(+k\) 的时候做一个半在线卷积,合并节点的时候做一个卷积,合并答案的时候做一个卷积,复杂度 3log,能过。
- P10046
绝对值是一个 max,求答案是一个 max,因此把 \(|x|\) 拆成 \(\max(x,-x)\) 之后,分别对 \(x,-x\) 求解不会使得答案变大。
问题变成,有一些三元组 \((a,b,c)\),每组里面选出一个数使得选择的 \(a,c\) 个数相同。可以反悔贪心,但是一个不需要脑子的做法是 random shuffle 后,可以证明 \(+1/-1\) 游走的上界期望是 \(\mathcal O(\sqrt n)\) 的,因此 dp 的复杂度为 \(\mathcal O(n\sqrt n)\)。
- P10047
考虑 dp 记录两边往中间匹配的状态,那么只可能有一边留下一个后缀或者一个前缀,直接 dp 就行了,细节比较多。
- CF1874D
首先推式子(细节不表),发现需要最小化 \(\sum\limits_{i=1}^{n}\frac{1}{a_i}\sum\limits_{j=1}^{i-1}a_j\),有一个简单的 \(\mathcal O(m^3)\) dp。
观察到如果存在 \(a_i>a_{i+1}\) 那么交换更优,所以序列一定是单调不降的,那么 dp 就变成调和级数的了!复杂度 \(\mathcal O(m^2\log m)\)。
- CF1874E
除了卡常,这题还是挺好的。
首先一个显然的 \(\mathcal O(n^6)\) dp:设 \(f_{i,j}\) 为长度为 \(i\) 的排列,代价为 \(j\) 的方案数。发现转移是一个卷积形式,可以 mtt 做到 \(\mathcal O(n^4\log n)\),但是没有前途。
考虑拉格朗日插值,即将 \(f_{i,*}\) 当成一个多项式,并代入 \(n(n+1)/2+1\) 个值进去得到结果,最后插值得到多项式。这样复杂度就是 \(\mathcal O(n^4)\) 了。
- P9331
一脸线段树优化建图。我们考虑怎么计算答案。我们现在要对于每一个点 \(i\),判断他是否能走到 \(1\sim n\) 的所有点。由于我们建的边都是区间批量连边的形式,所以如果 \(i\) 能走到 \(1\),那么 \(i\) 就能走到 \([1,i]\) 中的所有点;同理,如果 \(i\) 能走到 \(n\),那么 \(i\) 就能走到 \([i,n]\) 中的所有点。因此我们只需要把 \(1,n\) 作为源点跑反图的最短路即可,那么答案的一个上界是 \(dis_{1,i}+dis_{n,i}\)。
但是这两个 dis 的和可能计算了重复边。这好办,我们直接将这个值作为距离再做一遍松弛即可。
用 01 bfs 实现,时间复杂度 \(\mathcal O(n\log n)\)。
- P7360
分别考虑每个质因子,也就是 \([1,n/p]\) 中选出 \(k\) 个数的最大值之和。
考虑根号分治,对于 \(\le \sqrt n\) 的质数,枚举最大幂次计算;对于 \(>\sqrt n\) 的质数,质因子次数不超过 \(1\),这时候答案只和 \(n/p\) 相关,可以整除分块计算。
注意用扩展欧拉定理降幂。时间复杂度 \(\mathcal O(T\sqrt n\log n)\)。
- CF1174E
发现最大值一定是第一个数质因子幂次最多,接下来一直依次除掉一个直到 1 的过程,因此 gcd 中只会包含质因子 \(2,3\),且 \(3\) 的个数不超过 \(1\)。
那么就可以直接 dp 了,时间复杂度 \(\mathcal O(n\log n)\)。
- CF1554E
太神秘了,不会做。
只有 \(d\) 是 \(n-1\) 约数的时候有可能有解,这时候你发现当 \(d>1\) 时,解的数量不超过 \(1\)!具体而言,自底向上构造。
而总方案数等价于给 \(n-1\) 条边定向的方案数,因此计算 \(d>1\) 的答案之后,\(d=1\) 的答案直接用 \(2^{n-1}\) 减去即可。
- ARC104E
首先 \(\mathcal O(bell(n))\) 的枚举大小关系,这样问题变为长度为 \(m\) 的序列,每个位置的取值范围是 \([1,b_i]\),求得到一个递增序列的方案数。
首先对于后缀 \(b_i\) 取个 min,然后直接离散化了 dp 就行。具体而言,设 \(f_{i,j}\) 为前 \(i\) 个数,目前分到了第 \(j\) 段里,转移枚举这段数量即可,时间复杂度 \(\mathcal O(n^{n+4})\)。
- P8293
太厉害的题。
首先考虑如何刻画操作:遇到括号序列无非两种套路,第一种是把左括号当成 \(1\),右括号当成 \(-1\),观察前缀和序列;第二种是观察括号树。这题后者更有前途,我们考虑括号树。
每次操作相当于对于一个节点 \(u\),选择两个儿子节点 \(v,w\),并将 \(v\) 的所有儿子的子树接到 \(w\) 下面,再把 \(v\) 这个点接到 \(w\) 下面,代价为 \(Xc_w+Yc_v\)。
一个整体的贪心思路是从上往下依次下放。
接下来分类讨论 \(X,Y\)。用 \(m\) 代表当前层大小。
\(X=0,Y=0\):答案是 \(0\)。
\(X=0,Y=1\):考察同一层,在同层内最优的方案显然是把除了最大值以外的所有点都接到最大值底下,而这样做对于下一层肯定也是最优的,因为我们留下的点集是最小的。用 set 模拟贪心即可。
\(X=1,Y=1\):考察同一层,在同层内,假设保留了节点 \(x\),那么一定先把所有其他节点并到最小值上,再把最小值并到 \(x\) 上。我们发现这个贡献和 \(x\) 无关,实际上最小值被算了 \(m-1\) 次,其他节点都被算了 \(1\) 次,那我们希望下面的层更有,所以一定会选取最大值作为 \(x\)。
\(X=1,Y=0\):考察同一层,在同层内,如果固定了节点 \(x\),那么还是和上一种情况策略类似,会得到 \(m-2\) 倍最小值加上 \(x\) 的权值。但是这时候 \(x\) 究竟选择什么不是很好判断,因为有可能会下放一个最大值,且这个最大值一直没被算到。但是从整体的角度考虑,除了下放到最后一层的节点,每个节点恰好多贡献一次,因此我们需要最小化所有非末层节点的点权和加上每层最小值的 \((m-2)\) 倍之和。
对于 \(m=1\) 的情况,我们直接 skip。
对于 \(m\ge 3\) 的情况,我们可以留下一个非最大值,非最小值的节点,这时候必定最优。
对于 \(m=2\) 的情况,我们发现 \(m\) 序列应当形如 \(2,2,2\dots \ge 3\dots \ge 3,2,1\),而开头这段 \(2\) 的贡献只和下放到后面 \(\ge 3\) 的节点以及涉及到其相关操作的节点相关。这样我们就获得了一个 \(\mathcal O(n^2)\) 做法:枚举这个下放的节点,从头上开始模拟一遍。
有一个 \(\mathcal O(n\log n)\) 做法:排序之后,从小到大考虑下放的节点,用指针维护 \(\ge 3\) 段的信息。
我们发现,由于整体策略是要下放最大值或最小值,所以这一段也一定只会下放最大值或最小值。那么模拟两个数就够了!时间复杂度竟然是惊人的 \(\mathcal O(n)\)。
总结与启示:
-
遇到操作性最优化问题,首先观察操作的特征,用熟悉的数学语言/模型描述操作。
-
寻找必要条件,推导合法结果的形态。
-
对于不同情况分类讨论,仔细分析各种情况的策略。
- P9339
首先考察怎样的 \(c\) 是合法的。发现可以用二分图匹配刻画这个问题,那由 Hall 定理就可以推出一个限制,形如前缀和有一个上界。
现在问题变成从大到小选尽可能少的给定集合中的数,使得前缀和不超过上界,总和为 \(n\)。
这样就可以 dp 了,用 bitset 优化。时间复杂度 \(\mathcal O(\frac{n^2\log n}{\omega})\)。
- CF1943C
这题我会哦,真牛。
大胆乱猜!每次选直径的中点(如果长度为偶数那就两个都选),然后过了!
- CF1943D2
首先把操作转到差分序列上,用 Hall 定理刻画操作:每次相当于把一个 \(+1\) 和后面的 \(-1\) 匹配,因此合法的条件就是前缀的 \(+1\) 个数不少于 \(-1\) 的个数,用原序列表示就是 \(a_i\le a_{i-1}+a_{i+1}\),直接 dp 可以做到 \(\mathcal O(n^3)\)。
考虑容斥,钦定一些位置是 \(a_{i}>a_{i-1}+a_{i+1}\) 的,那么假设目前考虑到前 \(i\) 个数,如果要钦定 \(i-1\) 违反条件,那么可以直接对着 \(i-2\) 的 dp 转移,乘上一个系数即可,如果随意的话就从 \(i-1\) 转移。用前缀和做到 \(\mathcal O(n^2)\)。
- P3778
很明显的分数规划,考虑二分,现在相当于每段走过的路径买入卖出一个物品,赚到 \(c\) 块,消耗 \(t\) 时间的权值是 \(c-t\times mid\),要使得每一段路径的和大于 \(0\)。
首先预处理出每个点到另一个点的最短距离和最大收益,用 floyd 做到 \(\mathcal O(n^3)\),对于每次二分,其实是在做最长路,只不过是将每个连续段作为了一条边,还是用 floyd 实现,复杂度 \(\mathcal O(n^3\log V)\)。
- P3776
感觉有点简单。
考虑欧拉定理,现在问题变为计算白点个数,相邻(上下,左右)都是白点的对数,\(2\times 2\) 都是白点的个数,把贡献放在左上角,做一个二维数点即可(实际实现的时候需要补集转化,把 ban 了点周围设为无贡献)。
交上去发现 wa 了。因为还有一个 corner case,就是所有的黑点全部被包进去的时候会多贡献外围一个连通块。
- P10283
把问题放到 trie 树上考虑。当一个结束节点上有其他串或者还有儿子时,就必须得增加字符。
有两种决策:以 \(d'-d+2\) 的代价分裂一个叶子,或以 \(d'-d\) 的代价插入一个空节点,其中 \(d'\) 表示修改的点的深度,\(d\) 的对应不合法祖先的深度。
用可并堆维护贪心即可。
2024.4.1 End。
浙公网安备 33010602011771号