8.23

护照

在第 i 个点买一张票,就能在 [Li,Ri] 中任意行走,求从每个点出发,最少买几张票能走遍 [1,n]

tag:最短路,线段树优化建图。

题目的问题是求最少代价,于是我们发现题目很像一个最短路模型:i 向一个虚点 ui 连边权为 1 的边,ui[Li,Ri] 连代价为 0 的边。连边看起来很多,但是由于连边连向的是一个区间,我们只需要线段树优化建图即可。

考虑最终的答案是什么:由于连边是连向一个区间,所以对于点 i,所有买的票的并,也就是我们能走到的点,构成了一个大区间。所以走遍 [1,i] 的充要条件是走到 1 。因为 1 为该区间左端点。同理走遍 [i,n] 的充要条件是走到 n,因为 n 为该区间右端点。所以我们建反图并从 1n 分别跑最短路,每一个点的答案应该是到 1 的最短路加上到 n 的最短路。

然后我们发现这个不对,因为到 1 的最短路和到 n 的最短路会有重复的路径,这一段路径只会被计算一次。例如,从点 i 出发只需要买一张 i 的票就可以了。

我们如果设初始 dis1+disn 为初始答案 ansu,那么我们发现对于任意的 (u,v,w)ansvansu+w。于是我们考虑再次使用最短路,只不过这一次往优先队列中加入所有点作为源点进行松弛。

如果对算法进行思考,我们会发现只需要将所有票的虚点作为源点即可。原因如下:

  1. 对于线段树上的点,它们只负责联通原始图中有边的点,从其出发的边权值都为 0,因此不用松弛。
  2. 对于原有点,我们建的反图中必定有票的虚点连向原有点的边,因此只要不是无解情况,原有点必定会被松弛到。

Election

c,t 组成的字符串,每次询问一个区间,问至少需要删掉多少个 t,才能使在子区间任意一段前后缀里,c 的个数都不小于 t 的个数。

tag:线段树

两类字符比大小,很经典的操作就是把一个视为 1,另一个视为 1。这里我们把 c 视为 1,把 t 视为 1,那么原问题转化为:需要删掉多少个 1,才能使子区间任意一段前后缀和都不大于 0

考虑先满足前缀,再满足后缀。我们贪心地删除:如果这一个 1 会使前缀大于 0,我们才将它删除。这不仅用最少的次数满足了前缀都不大于 0 的限制,还将删除的点尽量右移。这会使后缀的修改更优。

考虑用变量描述前缀需要的最大删除数。我们设变量 prei 表示 li 的前缀和,可以发现当我们修改了 prei 变为 0 时,之后我们第一个修改的 prej 必定大于 prei,且修改的次数变为 prejprei。那么只满足前缀的答案是 max{prei}

现在考虑后缀。后缀的难点在于我们已经提前删除了一部分 1 了。于是我们考虑删除了多少。对于点 i,之前在满足前缀过程中删除的点为 max{prej}(ji),那么之后删除的点为 max{prek}max{prej}(ji)。所以若设原序列 ri 后缀和为 sufi,新序列后缀和为 newi,那么 newi=sufi(max{prek}max{prej}(j<i))

考虑最终答案 max{prei}+max{newj},把脑子放进垃圾桶,我们来推式子:

max{prei}+max{newj}=max{prei}+max{sufj(max{prek}max{prei}(i<j))}=max{prei}max{prek}+max{sufj+max{prei}(i<j)}=max{prei +max{sufj}(i<j)}

发现这实际上就是前缀的最大值加上在它右边的后缀的最大值。用线段树维护即可。

y-fast trie

给出常数 C 和一个初始为空的集合 S,你需要支持以下操作:

  1. 增加一个数 x,保证 xS 中没有出现过。
  2. 删除一个数 x,保证 xS
    在每次操作后,你需要输出 a,bS(a+b)modC。强制在线。
    n5e5

tag:模型刻画。

首先不难发现取模实际上把答案分成了两种,a+bCa+b

于是把 a+b 分类。分成 a+bCa+b<C。对于前者,我们找出 S 内的最大的两个数匹配即可。下文着重考虑 a+b 的情况。

对于 a,发现 a+b 随着 b 的增加而增加,直到 a+bC 为止。所以 a 会选择其中最大的 b。一种暴力的想法是,我们对于每个 a,找出使 a+b<Cb 的最大值。时间复杂度 O(qClogC),具体取决于集合内数的个数。

考虑优化这个暴力。对于每个 b,发现 a+b 随着 a 的增加而增加,直到 a+bC 为止。所以 b 会选择其中最大的 a。于是 ab 就从单项选择变为了双向选择。这是很好的,因为这就意味着所有 ab 两两匹配。

考虑维护匹配。对于增加操作,我们找到其作为 a 能匹配到的最大的 b,如果 b 没有匹配则可以直接匹配。否则若 a 比与 b 匹配的点更优,我们就扔掉 b 匹配的点,并将其与 a 匹配。如果匹配更新,则也要与当前答案比较。

对于删除操作,若没有匹配,可以直接删除。若有匹配,我们需要在删除 a 后另外为 b 寻找匹配。这是增加操作做的事情。因此我们删去两个数,并再次增加 b 即可。这些操作都可以使用 set 完成,时间复杂度 O(qlogC)

意外地难写。

posted @   _maze  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示