杂题选做

双向链接 博客园给我推荐的博文,可以看看(

1

2 卡爆了,不在这写了(

题目均会在题目链接后面简要讲述做法,代码我想想怎么办,我决定挨个放云剪贴板算了,不然太长了。

有些题知道做法就没什么意思了,所以我把 sol 提行写了(话说如果有人知道如何隐藏的话可以私信我谢谢喵)

有些代码可能在云剪贴板,这时可以访问 luogu.me 然后存档就可以看了(话说这个是我们 cqyc 的人搞得耶),当然还可以开 vpn,vpn 的话这里推荐 clash。(然后就是有时候可能会懒得贴代码)

P5234 [JSOI2012] 越狱老虎桥

图论,tarjan,边双联通分量。我の题解

P3242 [HNOI2015] 接水果

数据结构,树套树,深度优先搜索 DFS,最近公共祖先 LCA,整体二分 我の题解,这里在单独说一下整体二分怎么做,考虑分治,然后加入 \(\le mid\) 的,对于每个询问如果还不够那就放左边,否则放右边,然后减去左边的个数,询问就按值的大小放左边右边,然后直到 \(l=r\) 时求出答案退出,或 \(L>R\) 时没有询问退出。整体二分做法,确实快了进一倍

CF301D Yaroslav and Divisors

数据结构。注意到是个排列,所以最多有 \(n\ln_n\) 对,考虑在最大点处挂上,然后离线询问,树状数组查询即可。

CF797E - Array Queries

数据结构,dp,根号分治。考虑根号分治,小的预处理出 \(F\) 数组,大的不超过根号次,直接跑即可。

P4587 [FJOI2016] 神秘数

数据结构,可持久化线段树。 单次询问可以排序后看,假设当前能表示 \((1,x)\),那么 \(a_i>x+1\) 则输出 \(x+1\),否则 \(x = x+a_i\),其实就是要求左边的数的和 \(+1\le a_i\),我们考虑每次询问可以看(1,ans)的和为多少,\(sum\ge ans\) 那就跑到 \(sum+1\) 去,否则就输出 \(ans\),最多加 \(\log\) 次。分析也很有趣,假设上次是 \(x\),这次是 \(y\)\(sum = (1,y)\) 的值,那么 \(sum\ge y\),则说明 \(sum-(y-1)\) 就是 \((x+1,y)\) 中的值的和,至少为 \(x+1\),每次肯定增大一倍,所以最多 \(\log\),可持久化线段树就可以解决区间询问了。

CF958C3 Encryption (hard)

dp,Ad-hoc。 十分有趣的 trick 题。 注意到一个显然的 \(f_i = sum_i\left(\operatorname{mod} p\right)\),所以任意两个点 \(a,b\)\(f_a+sum_i-sum_a = f_b+sum_i-sum_b\left(\operatorname{mod} p\right)\),我们让 \(A = sum_i-sum_b\) 在模 \(p\) 意义下的值,\(B\) 同理,那么 \(f_a+A = f_b+B\left(\operatorname{mod} p\right)\),假设 \(f_a < f_b\),那么由于 \(A,B < p\),那么从 \(a\) 转一定不劣,若 \(f_a=f_b\)\(A = B\)。简单证明一下就是分讨,假设 \(f_a < f_b\left(\operatorname{mod} p\right)\),那么 \(A = B+f_b-f_a\),否则 \(B = A+f_a-f_b\),注意这里减是模意义下减,显然哪一类 \(a\) 都不劣,第一类要么 \(f_a,f_b\) 相差 \(>p\) 那么一定 \(a\),否则两个相等。所以找到关键转移点转移即可,复杂度 \(nk\)

P5621 [DBOI2019] 德丽莎世界第一可爱

CDQ,数据结构,树套树。 四维偏序模版题,有很多做法,先讲一个 CDQ套CDQ的,也可以套一个树套树,不过麻烦一点。考虑排序解决第一维,第二维二分解决,左边一半贡献给右边一半,然后单独跑两边,三维偏序就是两边分别按 \(y\) 排序然后归并,四维的话额外给个标记,表示是贡献点还是被贡献点,按 \(y\) 排序后放进去再分治,左边对右边,然后树状数组维护前缀最大值即可。注意如果你不想去重,那么一定要保证每个数相对顺序不变,所以建议使用 stable_sort 可以保持元素稳定性。代码

nth_element 可以做到 \(O\left(n\right)\) 求出第 \(k\) 小的值,十分有趣。用法,能够把一个指定位置上的位置放上正确的数。

CF1762F Good Pairs

数据结构。注意到 \(a_i > a_j < a_z\) 是没有必要的,同理 \(a_i < a_j > a_z\) 也是没有必要的,考虑对于一对 \(\left(i,j\right)\),若 \(\left(a_i,a_j\right)\) 一步可达,那么直接到了,否则 \(a_i\) 先跳到 \(a_{p_i}\)\(p_i\) 表示从前往后第一个可达的点,显然这么跳不劣,考虑怎么维护,注意到对于 \(a_i\) 可以处理 \(\left(a_i,a_{p_i}-1\right)\),然后在看 \(a_{p_i}\) 处即可。然后在讲一个其它做法,不过作者并没写,有问题也可以私信我。我们注意到如果 \(a_i > a_j\),然后 \(a_i\) 在到 \(j\) 前能到 \(\le a_j\) 的地方,那么一定能到,然后 \(a_i < a_j\) 同理,为了方便,显然 \(a_i < a_j\) 一定可以满足第一类,\(a_i>a_j\) 可以满足第二类,减去这两种,即 \(i-1\),然后求有多少个能 \(\le a_i\)\(\ge a_i\) 即可,然后可能会算重,删掉重复的即可,注意到可以平衡树或线段树,每次删掉一段数,然后新加一个大小为 \(siz+1\) 的点。

P7109 滴水不漏

构造题,交互题。虽然是很久之前做的,但因为比较有趣放这里来了(其实是因为做到下面那个想到这道题了,顺便写一下)假设每个的水可以清空,那么我们就可以二分放水了,如果 \(mid\) 处可以,就往大看,否则往小,操作是 \(2\log\) 次的。考虑可以把桶放后面去,如果突然满了,就测出当前的桶还剩多少水,然后简单算一下就是右边那个桶的水大小了,分析一下可以通过的。

CF1521C

构造题,交互题。眼前一亮思维题,注意到如果找到 \(p_i = 1\),然后让 \(x = n-1\),那么就是 \(\max\left(1,\min\left(n,p_j\right)\right)\),那么显然返回的事就是 \(p_j\),接下来考虑如何在 \(\frac{n}{2}\) 次就可以求出 \(p_i = 1\) 在哪里,套路的让 \(x = 1\) 执行 \(2\) 操作,那么就是 \(\min\left(p_i,\max\left(2,p_j\right)\right)\),显然返回 \(1\),那 \(p_i\) 就是最小值,返回 \(2\)\(p_j\) 有可能是,否则就都不是,把可能额外的判一下即可,然后就没了。code

CF1083C Max Mex

数据结构,线段树,树链剖分,dfs。从眼前一亮思维题来的,但是感觉没啥思维吧?一个显然的是,我们直接维护 \(0\)\(x\) 看是否可以构成一条链即可,这个显然可以合并吧,如果可以的话新的链肯定是原来的四个端点中的两个,判一下就好了,搞个线段树合并即可。然后接下来是闲话时间,我的想题思维其实是很跳跃的,我一开始想了一个维护初始最优的链是什么,发现每次可以去拓展,然后我就发现我需要看一段区间是否可以是祖先到后代的一条链,然后我发现可以,我突然发现那我直接维护 \(0\)\(x\) 这个是否构成链不就好了,然后发现也可以就完了,有趣有趣。code

CF31E TV Game

dp,搜索。 可以折半搜索这个太显然就不讲了,讲一个 \(n^2\) 做法,我们记 \(f_{i,j}\) 表示 \(i\) 个分给第一个,\(j\) 个给第二个的最小值,然后 \(g_{i,j}\) 记录转移即可,不过状态改为前 \(i\) 个选了 \(j\) 个给第一个就可以滚动数组优化了,空间就不高。code

K-D Tree题单和对应的题目简介

P5355 [Ynoi Easy Round 2017] 由乃的玉米田

闲话:lxl怎么在题目背景放神秘图片,有点恐怖。就普通莫队,注意到前三个其实是小清新,第四个大于 \(B\) 最多 \(\frac{n}{B}\) 次就枚举到头了,否则小的可以单独预处理,具体的思路和代码可以看云剪贴板。look

F. Serval and Brain Power 数据点分治,状态压缩(bitmasks)暴力枚举(brute force)动态规划(dp)贪心(greedy)模拟(implementation)字符串处理题解

P4262 [Code+#3] 白金元首与莫斯科

一个比较适合入门的插头dp板子。注意到每个点其实有三种可能,分别是不放,放右插头和放下插头,轮廓线跑就好了,然后朴素就是枚举每个点使其不能选然后跑,复杂度 \(n^2m^2\times 2^{m+1}\),虽然无法通过但也接近了,详情可以看代码code。然后我们考虑优化,发现瓶在于枚举了每个点变为障碍,我们直接想到通过正反跑轮廓线就可以做到不跑它,然后考虑合并就好了。注意到我们需要枚举的那个点作为障碍,就相当于不能向它连插头,然后其它的只要一致就行了。code2夹带私货(划掉)

arc108_e/E - Random IS

dp,期望。朴素的设 \(f_{l,r}\) 表示仅考虑 \(l,r\),选了 \(a_l,a_r\),然后选里面的期望长度是多少,转移是 \(f_{l,r} = (f_{l,k}+f_{k,r})/sum+1\),然后要满足 \(a_l < a_k < a_r\)\(sum\) 是满足条件的 \(k\) 的个数,然后随便优化一下,开 \(2n\) 个树状数组优化即可,具体可以看代码,\(n+2\) 是为了在两边放数然后答案就是 \(f_{1,n}\) 了。code

P9130 [USACO23FEB] Hungry Cow P

数据结构,线段树。什么楼房重建朋友,不过确实有点东西。考虑离散化后线段树维护,然后注意到一个东西,每次单点修改后,可能会解决掉后面的一段区间,假设我们能用线段树维护区间,然后信息合并快速,我每次就只用看一半了,类似线段树二分。考虑维护几个必要的信息:区间内的答案,能向后延伸几个,对于一个区间(如果有左右儿子)左儿子多出来的对右边的影响,该区间还有多少数没有选。考虑每次合并,如果左边延伸个数大于右边的,那么右边所有都可以,否则就去查询,具体可以看代码,也写了一些注释方便理解,注意事项也在云剪贴版里面。code

P12736 [POI 2016 R2] 圣诞灯链 Christmas chain

并查集,hash,二分,数据结构,倍增。 题解

P6021 洪水

DDP 模版,不过有个小挑战,就是尝试优化矩阵常数,发现大多数转移是没必要的,只用记两个数,转移只有三种,跑的特别快,离最优解只差一点点。 code

P3730 曼哈顿交易

莫队+值域分快,十分无脑,首先观察数据范围 \(1e5\),然后需要每个点出现次数,还要第 \(k\) 小,完全超出了正常数据结构的能力范围,直接根号算法即可,因为每个点权值都是 \(1\),所以值域是 \(O(n)\) 的,你每次删去原来的在加上,查询的时候大块跳小块暴力跑即可。code

P2824 [HEOI2016/TJOI2016] 排序

比较有难度的题了(也许是对我而言)。

线段树 二分 颜色段均摊(珂朵莉树 ODT)排序,珂朵莉树 ODT就不说了,考虑一个十分巧妙的方式,考虑二分答案,给 \(\le mid\) 的值变为 \(0\),其它变为 \(1\),根据最终结果继续下去,线段树简单维护即可。来总结一下吧,主要原因就是这个排序并不好做,而排序的关键就是需要相对大小关系,我们最终需要确切的数,就通过二分不断确定答案在哪个区间,最终将范围缩小至 \(1\),答案就出来了,哎其实我也不知道该如何想到,也许是熟能生巧吧( code

P5979 [PA 2014] Druzyny

比较有趣的一道题,如果没做过类似的算是比较有难度的题了。

dp,CDQ分治,线段树,笛卡尔树分治。 考虑朴素 DP 是十分容易的,\(f_i\) 表示前 \(i\) 个最多能分几段,如果不能合法就赋为 \(-inf\)\(g_i\) 表示对应的方案数,转移显然的是 \(n^2\)。考虑如何优化。

我们想快速转移,可是这些限制却十分恶心,朴素的搞肯定不行,注意到限制是 \(l_{max} \le z-i \le r_{min} (i<j\le z)\)\(l,r\)\(i+1\)\(z\) 中的,没有就分别是 \(0,n+1\)。考虑移项得到 \(l_{max}+i \le z \le r_{min}+i\),不妨让 \(l,r\)\(x,z\) 的,那么 \(i < x\) 的都至少得满足这个限制,然后在满足一些其它的,这启发我们分治,考虑左边的更新右边的,对于 \(\le mid\) 的部分,考虑用 \(l_{max} \le z-i \le r_{min} (i<j\le mid)\) 求出对于每个合法的区间,扫描线加线段树即可,然后枚举 \(mid+1\)\(r\) 部分,利用 \(l_{max}+i \le z \le r_{min}+i (mid+1\le j\le z)\) 求出合法的 \(i\) 区间,区间查即可,线段树维护区间最大值和对应的和即可。

判无解的话,就看 \(f_n\) 是不是 \(-inf\) 即可。 code

P3224 [HNOI2012] 永无乡

模版线段树合并/平衡树,并查集维护一下连通块,然后线段树合并,查询线段树二分,然后就没了。code

P11013 「ALFR Round 4」C 粉碎

本来打算放模拟赛T1但觉得这样太没素质了。

思维,dp。 定义合法删除点为删除的两个点之间是没有颜色一样的点,如果 \(i,j\) 是一对合法删除点,且 \(i\) 前面颜色一样的都匹配完了,那么答案至少为 \(j\),记 \(nxt_i\) 表示 \(i\) 前面第一个颜色一样的点。

考虑朴素 DP,根据结论颜色匹配每个颜色的点最多剩一个,那就记 \(f_i\) 表示 \(nxt_i\) 是否和前面的匹配了。如果 \(f_{nxt_{nxt_i}} = 1\),那么 \(nxt_i\)\(nxt_{nxt_i}\) 匹配可行,否则如果 \(nxt_i < j < i\) 中的 \(f_{nxt_j} = 1\),那也可以,此时 \(j\)\(nxt_j\) 匹配可以使得前面都被清空。若 \(f_{nxt_i} = 1,ans = i\)

优化很显然,发现就是求 \(nxt_i \le j < i\) 中是否有 \(f_{nxt_j} = 1\) 的,前缀和优化即可。code

P5889 跳树

线段树,哈希 hashing。线段树好题。考虑跳父亲是除二,但是到 \(1\) 就不行。考虑线段树合并,记录一下还要跳几次父亲,然后目前值是多少,显然每次合并最多向上跳 \(n\) 次,不然不符合题目了,所以复杂度可以保证,然后维护一下即可。code

P12479 [集训队互测 2024] 长野原龙势流星群

二分,平衡树,树形 DP,凸包。我也不知道为什么需要这些,我就用了优先队列。 题解

P12692 BZOJ3784 树上的路径

一个很典的求第 \(k\) 小的题,考虑二分第 \(k\) 小是多少,然后点分治看是否合法,精细实现可以做到每一次最多判 \(m\) 次,然后复杂度就可以做到 \(\left(n+m\right)\log^2n+n\log^2n\)code

P8346 「Wdoi-6」最澄澈的空与海

搜索,图论,二分图。有一定难度的思维题。做出这个题只需要一个核心结论,先容易发现,不合法就说明无解或有交替环,交替环的意思是一条非匹配边接一条匹配边构成了环。然后发现,如果每次搞完都有度数等于 \(1\) 的,我们就很好做。所以猜测度数均大于 \(1\) 一定不合法。无解情况不管,否则先找出一个匹配,然后对于每个点来说,都可以走一条匹配边和至少一条非匹配边,那么一定可以走出交替环,所以就不合法。否则你就直接类似拓扑的跑,每次加入度数为 \(1\) 的点,匹配完之后继续看,根据要求剩下的点度数至少有一个为 \(1\) 才合法,一直跑看是否能成功跑出来即可。 code

P4215 踩气球

线段树。先说一个无脑双 \(\log\) 做法,注意到每次删i之后就可以求出一个包含它的最长0区间(它不是就不管啊)把每个询问的右端点挂在左端点,然后求出 \(l\)\(i\) 中的那些点,然后就是需要里面 \(i \le x \le r\) 的个数,然后用 set 存就好了,小细节是 set 存的时候需要按顺序存,这样查出来之后也方便看个数,可能有值相同的查询时注意一点就好了。code

当然也有单 \(\log\) 做法。考虑一个类似合并的方式,我们每次操作如果执行到 \(a_x=0\),那么把两边的区间合并,答案就加上现在这个大区间的减去原来两个小区间的贡献,考虑并查集维护一下它们的下标和左右端点,然后可持久化线段树即可。

当然还有其他很多做法,例如基于答案上界最多为 \(n\) 用巧妙方式几乎每次更新都是有用的做法,不过就不一一讲了。

P10284 [USACO24OPEN] Splitting Haybales P

平衡树合并,平衡树,均摊分析。平衡树合并好题,而且笔者并不知道数字递增有什么用(

考虑插入回收删除算法,每次在左端点处加入,右端点加一处踢出。然后发现每次操作,其实就是把 \(x \le 0\) 的加 \(a_i\)\(>0\) 的减去 \(a_i\),然后区间 \(-inf,-a_i\)\(1,a_i\) 合并, 然后另外两个合并,打修改标记然后平衡树合并即可,复杂度可以分析。不过注意值相同的点需要有第二关键字,不然平衡树会退化,原因暂时不知道(

P6001 [CEOI 2016] popeala

DP,单调队列,双指针。考虑朴素 \(nm^2S\) DP 十分好想,\(f_{i,k}\) 表示前 \(i\) 个分成 \(k\) 段最小得分,转移也很容易,直接枚举每个点然后看是否有 \(0\) 即可。考虑优化,容易发现遇到 \(0\) 之后永远是 \(0\) 了,否则就是区间长度的贡献,考虑这样的 \(0\) 最多 \(n\) 个,可以分成若干段,不同段的系数 \(j\) 不一样( \(j\) 是造成贡献的个数),复杂度轻松做到 \(nmS\log m\),不过显然,对于每个区间,左右端点单调递增,维护一个双指针和单调队列即可,复杂度 \(nmS\)

P11894 「LAOI-9」Update

简单题。

倍增,差分,奶龙严选题,考虑差分求出每个点进行几次加,然后贡献变化其实就 \(\log\) 次,对于不同的贡献算一下用了几次即可。

P9021 [USACO23JAN] Subtree Activation P

树形 DP。简单推到题,推导发现其实本质上就是花费 \(2\times siz_i\) 的贡献可以时一条链都被覆盖,如果只覆盖 \(i\),贡献就是 \(2*(siz_i-siz_{son_i})\)\(son_i\) 是子树最大的孩子,即这些都是独立的,那我把重儿子最后跑就不用撤销了,然后就没了。也有其它做法可以看看。

CF425E Sereja and Sets

动态规划 DP。我去妙妙题,我赛时还没过呜呜呜。注意到在知道线段是啥后,可以朴素贪心 \(f_i\) 表示选了 \(i\) 最多分几段,然后找一个 \(r\) 最小的,更新到 \(f_r = f_i+1\)

然后考虑朴素 DP 就是 \(f_{i,j}\) 表示前 \(i\) 个选 \(j\) 段的方案数,然后考虑更新到 \(f_{k,j+1}\),根据贪心的,左端点在 \(i,k-1\) 之间包含左右端点,对应右端点应该都 \(> k\),这些线段总数就是 \((n-k)\times (k-i)\),即 \(2^{(n-k)\times (k-i)}\)然后对于点 \(k\),只要有至少一个左端点 \(>i\) 即可,即 \(2^{k-i}-1\) 种。然后转移过来即可。

P10706 悲哀(Sorrow)

话说我还抢到最优解了(

树上启发式合并,容斥,莫比乌斯反演,虚树。做法还不少,不过我不会莫比乌斯反演,所以只讲另外的。

注意要求 \(\gcd > 1\) 其实就是两个数有一样的因子,我们不妨仅考虑质因子,然后我们就可以容斥解决。

注意到 \(a_i \le 5e5\),所以不同质因子最多 \(6\) 个,这样的话,我们一个数最多和另一个数匹配 \(2^6-1\) 次。

我们对于每个数都存一下,然后我们对于一个点,可以给它的儿子按顺序便利,然后对于每个儿子先计算,然后在加进去,最后在算上自己的。具体的就是记 \(v_i\) 表示 \(i\) 这个数作为因子出现了几次,然后每次就把 \(a_j\) 的所有由不同质因子乘起来的数加一。然后根据 \(i\) 中不同质因数出现了几次给它一个容斥系数。

然后,这就是一个经典的树上启发式合并了,我们只需要先跑重儿子即可,这样可以直接利用重儿子的 \(v_i\)

对了,我们也有另一个办法,就是对于每个数,如果它是由若干不同质因子乘出来的,那么建立虚树,然后也可以用树上启发式合并,然后就没了。

P10812 【MX-S2-T3】 跳

动态规划 DP,前缀和。挺有趣的一道题。我们的核心问题是,前过去了之后有可能会回来。但是注意到一个东西,假设目前过程是 \(x,y,z\),然后 \(x > z > y\),然后 \(y\)\(x\) 的因数,那么到 \(z\) 之后就必须选择一个因数跳到 \(y\) 后面去。

我们不妨记 \(f_{i,j}\) 表示我目前在 \(i\),我只能到 \(i\)\(j-1\) 的地方的方案数。

转移十分简单,要么转移到 \(f_{i-1,i}\),要么枚举 \(z < j\),然后枚举因子 \(k\) 使得 \(k < i\),转移到 \(f_{i,k}\)

注意到每次转移都会算上 \(z < j\)\(f_{i,j}\),直接上前缀和优化即可,至于枚举因子嘛,用 vector 存每个数的因子,然后枚举因子,根据分析复杂度是调和级数 \(n^2\ln n\)code

P5188 [COCI 2009/2010 #4] PALACINKE

矩阵加速,容斥原理。这个题有点意思,当时还不会,现在练的多了就会了(

首先有一个很朴素的 DP,即 \(f_{i,S,j}\) 表示当前在点 \(i\),然后时间用了 \(j\),当前状态为 \(S\) 的状态,转移也很简单,就枚举能到的点然后看是否选这条边转过去即可。

然后,注意到 \(t \le 1e9\),直接做肯定不行,注意到这个式子看起来很可以矩阵优化的样子,唯一的问题是 \(S\) 怎么办。

注意到就四种可能,直接考虑容斥,即枚举 \(S\),然后边上有 \(S\) 中的值就一定不能选,否则就可以选,然后根据 \(S\)\(1\) 的个数给一个容斥系数,这里说个有趣的函数,'__builtin_popcount(s)' 可以返回 \(s\) 中有几个 \(1\),复杂度 \(\log\),当然手写也很简单,你考虑树状数组那个就是每次减去最后一个 \(1\),照着搞就好了。

然后就可以直接矩阵了,令 \(2\times n+1 = k\),考虑构建一个 \(k\times k\) 的矩阵和 \(1\times k\) 的矩阵。

\(1\times k\) 的矩阵就是存 \(f_{1,0},f_{2,0},...,f_{n,0},f_{1,1},f_{2,1},...,f{n,1},ans\)\(f_{i,0}\) 就是当前时间减一时的方案数,同理 \(f_{i,1}\) 就是当前的。

然后转移矩阵就自己退啦,我这里还是说一下吧。首先 \(v_{i+n,i} = 1 \left(1\le i \le n\right)\),这个显然,然后就是如果 \(i\)\(j\) 有连边,那么 \(v_{i+n,j+n} = 1\),还有就是所有可以选择的边 \(v_{i,j+n} = 1\),然后 \(v_{k,k} = v_{1+n,k} = 1\),即给答案。

然后就没了。code

P12930 [USACO4.3] 逢低吸纳 Buy Low, Buy Lower 加强版

动态规划 DP,树状数组。很典的题,只是我发现这个树状数组竟然也能优化,所以放上来让大家看看(

先离散化,对于每个 \(i\) 求出 \(f_i,g_i\),分别表示最大值和对应的方案数,转移时就是从 \(a_i+1,Mx\) 中选出最大值和所有最大值对应的方案数,线段树直接维护即可。但是树状数组也可以直接优化,在权值树状数组上的每个点维护一个二元组 \(\left(c_i,d_i\right)\),然后正常转移就行了。

注意到这个可是不能支持区间查的啊,但是我们难道不是询问的一段后缀吗,我们直接给这个翻转一下不就是求前缀了,然后就解决了,这个的代码我没写,我写的线段树的,树状数组的去看题解吧(

CF1830D Mex Tree

暴力枚举(brute force)动态规划(dp)树形结构(trees)*2800。没想出来看的题解,输。

注意到 mex 只有三种情况,所以答案上界应该是 \(n \times \left(n-1\right)\) 的不会很大。

然后我们想想贪心,一个很显然的是二分图交叉染色,答案大概就是 \(n \times (n-1)/2\) 的。

然后我们没啥想法了,不过看到上下界之间其实不大,也许会有点用处。

考虑一下朴素 DP,注意到我们只需要知道 \(f_{i,j,0/1}\) 表示 \(i\) 的颜色为 \(0/1\),然后仅考虑子树 \(i\) 会构成大小为 \(j\) 的连通块的最小影响是多少,因为只要走出这个连通块,那么贡献一定是二,注意到 \(0\) 连通块就都是 \(1\) 贡献,\(1\) 连通块恰恰相反。

答案是上界减去求出来的,所以我们希望转移时越小越好

转移直接枚举子树,然后 \(f_{i,j,z} = \min\left(f_{i,j,z},F_{i,k,z}+f_{son,j-k,z}+!z\times k \times \left(j-k\right)\right)\)

嗯,观察一下式子,注意到如果造成的影响 $ > n \times (n-1)/2$,当然就一定会劣,因为超出下界了。

大概就是根号量级的,也就是说我们转移不会转移超过根号,复杂度 \(n\sqrt n\),具体证明可以看 这篇题解,这里限于篇幅就不写了。 code

P3177 [HAOI2015] 树上染色

动态规划 DP,树形 DP。简单 DP 题,先转化一下,就是求所有点对距离在减去颜色不同点间两两的距离,f_{i,j} 表示子树 \(i\) 里面选了 \(j\) 个黑点的贡献,转移就是 \(f_{i,j}+\left(siz_i-j\right)\times \left(k-j\right)\times Z + j\times \left(n-siz_i-k+j\right)\times Z\),其中 \(Z\) 是到父亲的那条边的权值,\(siz_i\) 是子树大小,然后经典子树转移复杂度可分析到 \(n^2\),有一个有趣的分析方式是注意到这么搞可以理解为是从 \(a\) 里面选一个点,从 \(b\) 里面选一个点。

然后能选只会在 \(lca\) 处选,所以就是 \(n^2\) 的,即点对个数。复杂度讨论贴

P11069 「QMSOI R1」 生熏鱼

有趣的题,有两种很棒做法。

动态规划 DP,搜索,二分,背包 DP。考虑 \(2^n\) 枚举第一个是否选择。然后就分割成了若干段,每一段都是一致的,直接前缀和相减就能求出来,直接找到第一次不合法的二分看即可。

还有一种做法,就是考虑我们可以让第一次攻击不受,那么其实就是可以反悔一定量的血量,考虑 \(f_i\) 表示回复至少 \(i\) 的血量的最小代价,不行就不管,上限是 \(n\times C\),复杂度 \(n^2\times C + k\)

P11203 [JOIG 2024] 感染シミュレーション / Infection Simulation

线段树,树状数组。很有趣的题。十分显然的是,感染存在的时间一定是一段区间,我们只要知道这个区间就子只需要求每个区间与其的交集。

特判掉初始感染者区间 \(< x\) 的情况,然后我们其实就是要求最大的 \(r_i\),且 \(i\) 被感染了,考虑对于每一个人钦定一个唯一后继,具体就是对于区间 \(l_i,r_i\),找到 \(l_j,r_j\),满足 \(r_j \ge r_i\)\(l_j\) 最小,当然 \(j\) 不能等于 \(i\),然后能走说明 \(x\) 必须小于等于两者的交集才行,然后这个显然可以倍增优化,然后就能求出来最大的 \(r\) 了。

求出来之后就是一个显然的二维数点了,要求 \(r_i-l_i \ge x\)\(r_i-L \ge x\),一个显然的,不可能有 \(R < r_i\) 还合法的(不然 \(R\) 会增大啊),然后就很简单了,在线可以可持久化线段树,离线可以树状数组。

P1752 点菜

注意到求最小时间,看着就很像二分答案。

二分一个时间,然后对于两类特殊人群,选择其中一类贪心的选择,比如优先选择价格合理同时不好吃的,或则优先考虑符合美味度的同时最贵的,另一类就直接能选就选,然后看剩下的个数是否 \(\le mid\times x\) 即可,\(x\) 是不挑剔的人的个数。

用优先队列维护就好啦,复杂度 \(\log^2\)

P9266 [PA 2022] Nawiasowe podziały

DP,wqs二分,决策单调性。非常好的题,做法很多,复杂度 \(\log\)\(\log^3\) 不等。

在阅读前请先了解 在线决策单调性地皮还能单老哥分治做?,我用的这个做法,复杂度是 \(n\log^2\),想了解其他的可以看题解(

首先括号序列转化老经典了,左括号看成加一,右括号看成减一,合法就是 \(\min\left(a_l,a_{l+1},...,a_{r-1},a_r\right) = a_l = a_r\)

朴素 dp\(n^2k\) 的,考虑优化。

注意到此题是具有决策单调性的,具体证明很简单,请读者自行证明,这里提示一下,只需证明若 \(i < j < z\)\(i\) 转移到 \(z\)\(j\) 优,则 \(i\)\(z-1\) 也更优即可。还不知道可以看我代码下面的注释部分。

然后注意到这个贡献搞起来很不舒服,考虑参考 CF868F 直接莫队搞(是的这个确实可以莫队),具体如下:

先对于每个点求出左边右边第一个比它大的,然后求出 \(L_i,i\)\(R_i,i\)\(=a_i\) 的个数,在莫队时左指针 \(l\) 移动时看 \(R_{l-1}\)\(r\) 的大小关系,注意左指针移动是看 \(l-1\),因为我是减去左边,右边就看 \(r\)

给个代码方便理解:

//X,Y双指针 
//v1_i:左端点为i的个数,v2同理
//S_i,(L_i,i) 中等于a_i的个数,S1_i同理 
while(Y < r)
{
	Y++,v1[a[Y-1]]++,v2[a[Y]]++;//加/减的顺序不重要,不可能有a_i=a_{i+1}
	if(X <= L[Y]) sum += S[Y];//只能选这么多 
	else sum += v1[a[Y]];//一定没有比它大的,直接选完 
}

然后复杂度来到 \(nk\log\),容易发现此题可以 wqs 二分,因为分的越多答案越小,然后改变量也会越来越小。

然后用上诉决策单调性分治做法可以做到 \(n\log^2\)

个人认为,细节问题的话就是注意要开两个莫队,然后要明白莫队在干什么,我一开始写的 \(a_l\),后面才想起该是 \(a_{l-1}\)code

P2839 [国家集训队] middle

很有趣的题呢。

可持久化线段树,分块,二分。容易发现,其实就是必须选择 \(\left(b,c\right)\),然后可以拓展,但是不能超过 \(\left(a,d\right)\)。我们肯定不能把原序列排序,复杂度肯定吃不消,考虑在此题中中位数本质上是什么,对于 \(x\),如果 \(<x\) 的数的个数 \(\le \frac{n}{2}\),且 \(\le x\) 的个数 \(> \frac{n}{2}\),那么 \(x\) 就是中位数,这里我们认为除法是自动向下取整。

这玩意也不好搞啊,不过我们可以知道一个事实,如果如果 \(<x\) 的数的个数 \(\le \frac{n}{2}\),那么中位数至少为 \(x\),所以我们可以二分。

对于这个我们有两种经典套路可以解决,一种是把 \(<x\) 的视为 \(-1\)\(\ge x\) 视为 \(1\)
,则如果区间 \(\ge 0\),则中位数至少为 \(x\)

还有一种是转化为 \(2\times sum \le n\),因为左边必为偶数,所以就算右边是奇数除二会向下取整也没事,这里用的第一种,所以这个就不细说了。

不过每次都把 \(<x\) 的视为 \(-1\)\(\ge x\) 视为 \(1\) 复杂度还是不好,注意到没有修改,我们可以提前预处理。

考虑可持久化线段树,看一下我们需要什么,首先我们要知道 \(\left(b,c\right)\) 的区间和,然后需要知道一个前缀最大值和一个后缀最大值,直接拿线段树维护即可,具体实现可以看代码,有注释。code

P6583 回首过去

数论,整除分块。有趣的题,首先显然是十进制有限小数必须分母分子约分后分母是 \(2^x\times 5^y\) 的形式。

大概就是 \(\frac{a\times c}{b\times c}\),其中 \(a\) 任意,而 \(b\)\(2^x\times 5^y\)\(c\) 是不含 \(2\)\(5\) 的这两个质因子的数,我们随便枚举一个,比如枚举 \(c\),就可以做到 \(O\left(n\right)\)

考虑整数分块,不过 \(c\) 是不含 \(2\)\(5\) 的这两个质因子的数,这个嘛直接容斥掉就好了。

具体的就是减去 \(2\) 的倍数的和 \(5\) 的倍数的在加上 \(10\) 的倍数的。

完事这个 \(a\) 我们是知道个数了,这个 \(b\) 嘛,考虑越到后面选择越少,而仅由这两个乘起来的数很少,暴力跑出来然后指针移动一下就好了。 code

P12391 「RiOI-6」帝国少女

Ad-hoc。一般人都可以发现这个 \(m>2\) 应当都是一个做法。

那就分类讨论呗。对于 \(m=2\) 的,其实就是对于一个序列,然后 \(12\) 或者 \(21\) 染色,看哪一个相同的多一点, 然后我看了题解,它告诉我,套路的讲奇数位翻转,那么一个子段的操作次数就是 \(1\) 的个数与 \(2\) 的个数的最小值,然后它说 \(\min\left(x,y\right) = \frac{x+y-\left|x-y\right|}{2}\),将所有 \(2\) 替换成 \(−1\),前缀和一下变成任意两数差的绝对值之和,然后直接排序做,这样就一定是后面的减前面的,最后答案乘二就好了。

至于 \(m>2\),就是对于一段值相等的,答案就是 \(\frac{len}{2}\) 向下取整,原因很显然,是奇数的修改在内部肯定没事,为偶数只需要与相邻的为偶数的操作方式不一样即可(即一个是修改 \(1,3,5...\),一个是修改 \(2,4,6...\))。

对于一段有四种情况出现:

  1. 完整出现。
  2. 前缀
  3. 后缀
  4. 完全包含了这次询问(注意不要算上第一个的)

分讨一下即可。code

CF475E Strongly Connected City 2

给的洛谷链接,可以点一下跳到 CF。

DFS及其变种(dfs and similar),tarjan,bitset。

随便写的题解,将就看吧

P11189 「KDOI-10」水杯降温

神题,磕头了。

动态规划 DP,贪心,二分,树上差分。非常好的一道二分题。

基本上所有做法都可以归为一类,所以我只讲一个方便点的,还有一个开始方式可以看这篇,他是先执行二操作在执行一操作,然后观察性质(显然跟操作顺序无关)。

考虑树上差分,\(A_i = a_i-a_{fa_i}\),那么操作转化为:

  1. 单点加一。
  2. 根节点减一,然后选择一个叶子 \(u\),然后对于根节点到 \(u\) 路径周围的点都加一。

所以容易发现若存在非根节点 \(A_i > 0\),则一定无解。

然后,如果 \(A_1 \le 0\),则一定有解。

否则,我们考虑树形 dp,因为对于一条 \(1\)\(i\) 的路径,接下来只会看 \(i\) 的儿子,所以我们可以直接设 \(f_i\) 表示仅考虑 \(i\) 子树最多可以执行多少次刮风(第二个)操作。

首先叶子结点的 \(f_i = \inf\),否则,对于点 \(u\),考虑每个儿子贡献多少,比如是 \(x_i\),那么 \(0 \le x_i \le f_i,sum-x_i \le -a_i\)\(sum\) 是所有 \(x_i\) 的和。

转化一下就是 \(\max\left(0,sum+a_i\right) \le x_i \le f_i\),注意到 \(f_i\) 就要取 \(sum\),显然 \(sum\) 取值是一段前缀,直接二分求就好了。

对于这种区间取值的,直接记两个值,一个是左端点的和,一个是右端点的和,然后只需要值在里面就可以表示出来,具体实现看代码。 code

P12009 【MX-X10-T5】[LSOT-4] Masuko or Haru?

hash,克鲁斯卡尔重构树,异或

题解

P11503 [NordicOI 2018] Nordic Camping

单调队列,二分,扫描线。

煎蛋题,求出 \(S_{i,j}\) 表示从 \((i,j)\) 开始的最大值,然后扫描线+单调队列即可。

精细实现可以做到 \(nm+q\),我 \(S_{i,j}\) 直接二分搞得,也可以尝试一下单调队列优化。

code

CF512E. Cycling City

dfs及其变种,图论。

题解

posted @ 2025-06-29 15:18  kkxacj  阅读(55)  评论(0)    收藏  举报