那些你不要的 10.03 - 11.18
10 月
10.03
10.04
10.05
10.07
10.16
10.18
10.19
10.21
10.30
11 月
11.01
11.06
11.13
NOI Online 2022
AHOI 2022
2022 年 5 月
5.17
5.18
5.19
9 月
9.3
T1 荤数(brime)
暴力枚举 \([1, K]\) 里面的质数筛一下。
T2 序列(sequence)
设 \(f_i\) 表示考虑到前 \(i\) 个位置的本质不同的子序列个数,设 \(lst_i\) 表示 \(a_i\) 上一次出现的位置,则 \(f_i = 2\times f_{i - 1} - f_{lst_i - 1}\)。
若确定了前 $n $ 个位置,第 \(n+1\) 个位置显然贪心填 \(lst_i\) 最小的一定最优,在不超过 \(\mathcal O(n)\) 的位置后剩下的一定是循环节,所有位置一定是每隔 \(m\) 个出现一次。后面的转移矩阵快速幂即可。
T3 IIIDX(iiidx)
推一下柿子,用线段树维护矩阵连乘。
T4 异常(incepttion)
求出每个点距离它最近的关键点的距离 \(f_i\),答案就是 \(\max f_i\) 。
对于关键点建出虚树,虚树上的点可以直接换根 dp 记录最大次大得到。
剩下的非虚树上的点有两种情况,1 是虚树上的点的子树,这一部分可以维护一下区间最大深度,查询一定是一段连续的区间。
2 是两个虚树上的点夹着的点,先可以二分得到 \(x, y\) 分别管辖这条链上的范围,设 \(h_x\) 表示 \(prt_x\) 的子树内不包含 \(x\) 子树的最大深度,可以倍增维护 \(h_x\),设 \(l - y\) 都归 \(y\) 管,等价于查询区间的 \(h\),\(prt_l - x\) 同理。
时间复杂度 \(O(n\log^2n )\)。
9.6
T1 世界征服者(vanquisher)
设 \(f_{i, j}\) 表示考虑到前 \(i\) 个人,目前 1 操作用了 \(j\) 次的最小二操作。暴力转移即可。
T2 悲伤(sorrow)
考虑线段树 + 堆来维护,每个节点保存的堆表示整个区间的可重集,操作 1 直接在堆放入 \(\log n\) 个元素即可。操作 2 先查区间 \(\max\) ,设为 \(d\),注意到我们不能直接定位 \([l, r]\) 后对 \([l, r]\) 的堆进行操作,因为当前区间的 \(\max\) 可能是由其父亲提供的。考虑定位到最浅的有 \(d\) 的区间(若存在,其堆中最大值一定是 \(d\),否则和 \(d\) 的最大性矛盾),将一个 \(d\) 删除,再加入 \([L, R] / [l, r]\) 的所有区间。
若我们能在 \(\mathcal O(\log n)\) 的时间内找到一个要删除的标记,时间复杂度即为 \(\mathcal O(n\log^2)\) 的,因为存在的总标记个数不超过 \(n\log n\)。只需要在区间 \(\max < d\) 时退出即可。
T3 期望(expect)
枚举连通块算贡献,设 \(f_S\) 表示使得 $S $ 连通的方案,转移可以容斥,枚举 \(\mathrm{lowbit}(S)\) 所在连通块即可转移。
答案就是说 \(\sum f(S) \times g(S)\),其中 \(g(S)\) 表示 \(S\) 所有点和 $U / S $所有点不连通的概率。
T4 幸终(happyend)
朴素 dp 是考虑 \(dp_x\) 表示 \(x\) 为根的答案,转移枚举 \(x\) 子树内的节点 \(y\),所有挂在 \(x - y\) 链上的点上的 dp 值求和,再根据题目所给计算方式计算 \(x - y\) 的贡献。
先计算 \(mxd - d_x\) 的前缀和,转移变成 :\(dp_x = \min(sum_y+rec+(-h_y+C_y^2 \times (d_y - d_x+1) +C_y(sd_y - sd_{prt_x})))\)。
\(sum_y\) 表示 \(y\) 子树内所有 dp 值,\(rec\) 可以在转移时累加 \(sum_x - dp_y\),看做常数。 将 \(d_x\) 看做一个未知量,转移是一个二次函数的形式,交点可能不止 1 个,无法直接用李超线段树计算。
真的无法计算吗?我们猜测任意两个二次函数最多只有一个交,通过验证发现是对的。于是类似维护一次函数,维护一个二次函数即可。
需要支持李超线段树合并,转移 \(y\) 时,将整个 \(y\) 的转移加上常数 \(sum_x - dp_x\),再维护一个 tag 即可。
总结:
- 标记永久化也可以对一段区间进行撤销。
- 对于连通的状压 dp,一般都是正难则反,枚举某个关键点的连通情况变成子问题。
- 李超线段树不一定只能维护一次函数,对于任意交点 \(\leq 1\) 的直线,单调性只有两种的,都可以直接维护。
9.12
【JOI Open 2016】摩天大楼
将 \(A_i\) 排序后, 考虑任意 \(A_i - A_j = \sum\limits_{k = i}^{j - 1}A_{k+1}- A_{k}\)。考虑微元贡献,\(A_{k +1} - A_k\) 的贡献是满足 \(i \leq k, j>k\) 的二元组个数。
直接对每个 \(k\),考虑相邻 \(p_i\) 的大小不太容易。对于一个最终排列,我们只考虑 \(\leq k\) 的数构成的序列,设有 \(i\) 个连续段,\(o\) 个为边界(\(o \leq 2\)),则相邻的两个连续段以及非边界连续段中间都是 \(>k\) 的,必然产生贡献,考虑以连续段个数和当前总贡献计算答案。
设 \(f_{i, j, k, l}\) 表示考虑 \(\leq i\) 的所有数,目前有 \(j\) 个连续段,只考虑 \(\leq i\) 的 \(A_{k+1} - A_k\) 贡献为 \(k\),边界个数为 \(l\) 的方案,新的贡献为 \(k+(2j- l) \times (A_{k+1} - A_k)\),转移对 \(i\) 是否加入一个新的连续段,是否合并连续段,是否增加边界进行讨论(以下省略 \(i \to i+1\) 的转移):
- 作为一个新的连续段:
- 插入不为边界的空隙:\(f_{j+1, k', l} \leftarrow (j+1 - o) \times v\)。
- 插入边界:\(f_{j+1, k, l+1} \leftarrow (2 - l) \times v\)。
- 合并两个连续段:\(f_{j - 1, k', l} \leftarrow (j - 1) \times v\)。
- 添加到非边界的端点:\(f_{j, k', l} \leftarrow (2j - l) \times v\)。
- 让一个连续段成为边界:\(f_{j, k', l+1} \leftarrow (2 - l) \times v\)。(容易漏掉!!!)
答案是 \(\sum f_{n, 1, i, 2}\)。 时间复杂度 \(O(n^2L)\)。
【JOI 2014 Final】裁剪线
【JOISC 2017 Day 1】烟花棒
二分答案 \(V\),假设所有人的速度都是 \(V\)。最优策略一定是:初始所有不是 \(k\) 的人都往 \(k\) 跑,\(k\) 选择左 / 右方的人传递,传完后 \(k\) 个和这个人一起以相同的目标前进,总可燃放时间加上 \(T\),以此类推。
注意传递完后所有人的相对顺序不变,而时间是一个常数 \(\dfrac{d_i - d_{i - 1}}{2V}\),可以转化为如下问题:
长度为 \(n\) 的数组,你有初始权值 \(T\),到达每个位置有代价 \(a_i\),代价完后有收益 \(T\),规划一条从 \(k\) 开始的路线,使得经过所有点的同时,任意时刻收益 \(\geq 0\)。
显然 dp 是没办法做的,考虑贪心。
每次找相邻的代价最小的 \(a_i\) 肯定是不对的,因为可能一个很大的代价后跟着的都是代价很小的。
我们可以把一段连续的区间看做一个二元组 \((mx, profit)\),表示若你有至少 \(mx\) 的收益,你就可以得到 \(profit\) 的代价。显然我们可以模拟操作,若 \(profit \geq 0\),一定不会和下面一个点接上,即使下一个点很优。
求出往左往右对应的二元组(保证所有 \(profit \geq 0\))后,我们可以贪心选择 \(mx\) 最小的,若不存在显然无解。否则,还剩余一段前缀和一段后缀未选择,这些前后缀满足任意部分和 \(\leq 0\)。
倒着操作这些前后缀,先算出最终的收益,将 profit \(T\) 和代价 \(a_i\) 互换再做一遍即可。
时间复杂度 \(O(n\log n)\)。
【eJOI2018】循环排序
若有 \(i_1 \to i_2 \to \dots i_k \to i_1\) 的置换,设 \(b_i\) 表示 \(a_i\) 排序后的结果,等价于 $b_{i_k} \to a_{i_1}, a_{i_1} = b_{i_2} \to a_{i_2}, \dots $,对所有 \(b_i \neq a_i\) 的 \(i\) 连边 \(b_i \to a_i\),则一个欧拉回路就是一组合法的解,且一定是操作次数最小的解。
但由于题目要求最小化操作次数,我们可以将若干个操作合并起来,例如 \([6, 5, 4, 3, 2, 1]\) 本来是 \((1, 6),(2,5), (3,4)\),我们可以 \((1, 6, 2, 5, 3, 4)\),再对没到目标位置的数一起做一遍 \((3, 2, 1)\)。
容易发现,合并 \(k\) 个环成一个操作的额外操作次数为 \(k\) 次,那就能合并的就合并就好。
时间复杂度 \(O(n)\)。
总结:
- JOI 题,思维量恐怖如斯。
- 当一些贡献很难直接统计时,可以考虑“微元法”,即考虑足够小的子问题对总答案的贡献。对连续段进行 dp,要考虑是否加入新的连续段,合并连续段,变成边界等情况。不失为一种好的 dp 方法。
- 一些先入为主的观察和推论总是好的,先列举出可能的形态,再对不合法的逐一排除。贪心题很容易举出反例,重要的是对反例进行分析得出新的模型。收益 - 花费题一般都可以看做二元组 \((mx, profit)\)。
- 排列置换题不一定都是环,也有可能是欧拉回路。将多个环变成一个环只用额外\(环的个数\) 个操作。
9.22
T1 哼串计数
枚举 13 和 24 字符,归并排序算一下答案,dp 一些东西就可以了。
时间复杂度 \(O(|\sum|n)\)。
T2 金银变换
做“按照某种方式交换,是否能把一个数组变成另一个数组”首先的切入点是:
- 下标是否有同余关系?
- 若有,不同剩余系是独立的,但不完全独立。对一个剩余系操作,对其他剩余系影响是什么?
- 逆序对发生了什么样的变化?
对于本题,显然能交换的位置 \(\bmod k\) 同余,若同一个剩余类不能完全匹配则无解。
否则,通过大量手玩发现,只有所有同余类逆序对奇偶性相等,必然有解,否则无解(每个 \(a_i\) 的值是 \(b_i\) 顺序对应的下标)。
T3 枝江旧事
先找原根,特判没有赋值操作,此时答案唯一。
否则等价于 01 背包,初始将所有赋值操作的容量设为 1,然后跑 01 背包,时间复杂度 \(O(np)\)。
考虑到我们只用求是否存在,若每个容量我们能花一定的代价找到它并修改,保证以后不再访问,就是能保证复杂度。
还是依次加入修改操作,考虑类似线段树的递归过程,每个位置维护一个 hash 表示当前是否存在,则将 \([l, r]\) 全部 \(+x\) 后的 hash 值是容易得到的,若 \([l, r]\) 和 \([l+x, r+x]\) 的哈希值不相等,则必然存在可以被 \([l, r]\) 中 1 修改的 \([l+x, r+x]\),找到修改的位置即可,这样找到一个并更新的复杂度是 \(O(\log^2 n)\)。
时间复杂度 \(O(n\log^2 n)\)。
T4 膜皮圣经
\(d\) 做个前缀和,于是区间 \([l, r]\) 的答案就是 \(c_k \times (d_{r - 1} - d_{l - 1} +\min(d_{r - 1} - d_{k - 1}, d_{k - 1} - d_{l - 1}))\)。由于 \(c, d\) 是相独立的,将 \(d\) 平移一下就是 \(d_r - d_l + \min(d_r - d_k, d_k - d_l)\)。
建出笛卡尔树,经过区间 \([l, r]\) 最大值 \(p\) 的区间容易计算贡献,考虑不经过的 \([p+1,r]\) 的贡献,根据经典套路在笛卡尔树上每个点维护最靠左的到区间所有点的答案,对于 \([l, p - 1]\) 只用将区间翻转即可。
假设当前在 \(p\),已经处理完 \([l, p - 1]\) 和 \([p+1, r]\) 的贡献,则 \(x \in [p+1,r]\) 的贡献为 \(c_p \times (d_x - d_l + \min(d_x - d_k, d_k - d_l))\)。当 \(d_x - d_k \leq d_k - d_l \Rightarrow d_x \leq 2d_k - d_l\) 时,\(val = c_p \times (d_x - d_l+d_x - d_p)\),否则 \(val = c_p \times (d_x -d_l+d_p - d_l)\),容易发现这是一个关于 \(d_x\) 的一次函数,直接上李超线段树维护区间直线即可。
时间复杂度 \(O(n\log^2n)\)。
9.24
T1 小D的序列
若 \(a\) 能成为答案,则 \(sum = \dfrac{a^n - 1}{a - 1}, prod = a^{\frac {n(n - 1)}2}\),显然 \(a\) 也在给定序列里面,\(O(\log n)\) 判断即可。
T2 小S排座位
直接对每个 \(i\) 找到最小的 \(a_j \geq a_i +k\) 的 \(j\) 不对,但只要将所有 \(\leq \dfrac n 2\) 和 \(> \dfrac n 2\) 配对一定是最优的,正确性显然。
T3 小K的外挂
对每个位置 \(i\) 预处理从 \(i\) 往右跳一步能到的最靠右的位置,若没有修改或者修改对答案没有影响直接倍增跳就是答案。
否则设影响区间为 \([l, r]\),先跳到第一个 \(\geq l\) 的位置,维护能跳的次大值,设为 \(g\),在 \([l, r]\) 时用 \(g\) 来跳,直到当前最大值不是 \([l, r]\) 再用 \(f\) 跳。
时间复杂度 \(O(n\log n)\)。
T4 小Z的作业
等价于区间加边,询问全局连通块是否 \(\leq k\),对每个 \(r\) 维护 \(pre_r\) 表示最靠左的合法的 \(l\) ,用 LCT维护即可。
时间复杂度 \(O(n \log n)\)。
9.26
T1 彩票
根据题目随便模拟一下就好。
T2 战斗
由于 \(n \leq 500\) 不难想到区间 dp。由于要求的是第 \(k\) 个人活到最后的概率,时光倒流后,变成两个人打,赢的那个人复活输的那个人,设 \(dp_{l, r}\) 表示 \(l, r\) 都已经复活,\((l, r)\) 都比 \(l, r\) 晚复活的概率,转移枚举 \((l, r)\) 中最先复活的人 \(k\),再看他是被 \(l\) 还是 \(r\) 复活的,答案是 \(dp_{0, k} \times dp_{k, n+1}\) 。
T3 扑克
显然乘积不会很大,因此组成乘积的这些数的和不会很大,枚举和,可以得知剩下的和,继而得知当前乘积,再检验是否合法即可。
和只用最多枚举到 \(10000\),判断只用分解质因数后看剩下的所有质因子次数 \(\geq 0\) 即可。
T4 排队
显然可以把连续段缩起来,暴力的想法是对每个颜色维护一棵平衡树,全局维护一棵平衡树,每次在同色平衡树中二分最靠前的位置插入,时间复杂度 \(O(n\log^2 n)\),由于平衡树的大常数,无法通过。
为什么我们要维护平衡树?因为要得知所有人的相对位置,但是新插入的人不会对后面的人产生影响,换而言之,插入一个人对同色连续段的影响要么是将某一段的个数 + 1,要么在末尾新加入一个连续段,可以直接在线段树上维护,此时查询只用在线段树上二分了。
时间复杂度依实现可做到 \(O(n\log n)\) 或 \(O(n\log^2 n)\)。
9.27
T1 机器人与宝藏
模拟。
T2 子集和
对每个 \(r\) 求出最靠右的满足条件 \(l\),有一个显然的回退背包做法,时间复杂度 \(O(nm)\),无法通过。
注意到我们只要求可行性,考虑用 bitset 来优化,但 bitset 不能支持记录方案数,我们就只能添加而不删除地维护背包。
经典的维护不删除的双指针,可以想到 baka's trick,即找一个端点 \(mid\),预处理所有 \(mid\) 后缀的背包,从 \(mid\) 开始前缀的背包。当然这个题只用维护当前前缀的答案,每次还是尝试移动左端点,判断合法只用两个 bitset 与起来存在 \(m\) 即可,若移动到 \(>mid\) 的位置则直接将 \(mid\) 右移到当前位置,注意到此时合法的左端点不会小于 \(l\),因此暴力移动预处理复杂度是 \(\mathcal O(\dfrac{nm}{\omega})\)。
T3 机器人填数
简单想法是设 \(dp_{x, i}\) 表示 \(x\) 子树有 \(i\) 中颜色的方案,因为要求“恰好" \(i\) 个至少出现一次,不难想到容斥,钦定 \(j\) 个位置不填,则一个 \(dp_{y, k}\) 的贡献是 \(\dbinom{i - j}k \times dp_{y, k}\),最后容斥就是答案。
然鹅复杂度达到了 \(O(nk^2)\),无法通过。首先应该优化是缩减 dp 维度,为什么我们要记颜色数?因为存在 -1 的情况,若一个 \(x\) 的父亲是 -1,我们显然可以将 \(x\) 接在第一个不是 -1 的父亲上,显然不影响答案,同时叶子节点一定是 1,这样就不存在 -1情况。
这样还是 \(O(nk)\) 的,但我们发现 \(x\) 子树内本质不同的 \(c\) 只有 \(O(\sqrt n)\) 中(经典结论),因此对于相同的 \(c\) 一起计算,时间复杂度就是 \(O(n\sqrt n)\),可以通过。
T4 字符环
有点不可做。
10.04
T1 皮胚
根据题目意思 dp 就好了。
T2 核冰
先不考虑单点修改,是一个简单是贪心:从小到大考虑所有数,设 \(occ_i\) 表示 \(i\) 的出现次数,尽可能多的进位,但要保证当前位至少有一个(假设 \(occ_i \geq 1\))。
加上单点修改线段树即可,若加上 1 当前位 \(\geq 3\) 就找到当前位开始的连续的 2 的个数,区间赋值为 1,否则直接单点修改。
减去 1 同理,时间复杂度 \(O(n\log n)\)。
T3 方珍
暴力直接二分,看当前 \(\geq k\) 的区间 mex 的个数即可,时间复杂度 \(O(nm\log n)\),显然无法通过。
考虑不二分,将 \(w_i\) 从大到小排序后,答案至多是 \(w_1 + n\),直接扫一遍可以去掉 \(\log\),时间复杂度 \(O(nm)\)。
T4 术劣
若一个数列排序后是等差数列,则至少存在一对相邻两个数之差为公差,即 \(gcd(a_2 - a_1, a_3 - a_2, \dots, a_n - a_{n - 1}) = d\)。
对于原问题扫描线,维护一个 \(r\) 所有 \(l\) 的答案,一个数列合法当且仅当 \(\max - \min = (r - l) \times d\),$\max $ 和 \(\min\) 的维护非常典,不多讲。
根据上面的推论, \(d\) 的计算可以算出相邻两项的 \(\gcd\),用一个栈保存所有不同的 \(\gcd\) 以及对应的区间,栈的大小只有 \(\log V\) 个,每次新加入一个 \(a_i - a_{i - 1}\) 最多影响 \(\log V\) 个点,直接暴力即可。
线段树维护区间 \(\min\) 以及个数,时间复杂度 \(O(n\log^2 n)\)。
10.05
T1 矩形A
签到。
T2 序列B
欧拉反演后用狄利克雷后嘴和计算。