IOI 2020 集训队作业
#01 CF504E Misha and LCP on Tree ⭐⭐⭐
给定一棵 nn 个节点的树,每个节点有一个小写字母。
有 m 组询问,每组询问为树上 a→b 和 c→d 组成的字符串的最长公共前缀。
n≤3×105,m≤106。
哈希满足可减性,很方便合并。
所以考虑利用 f(u) 表示 u→1 的哈希值,同理用 g(u) 表示 1→u 的哈希值。
回答询问的时候二分答案 l,每次利用长链剖分找到这段长度为 l 的路径的端点,LCA 使用 ST 表维护。
哈希要写双模,但不要被卡常。
时间复杂度 O(nlogn)。
#02 CF505E Mr. Kitayuta vs. Bamboos ⭐⭐
给定 n 个数 h1⋯n。
你需要进行 m 轮操作,每轮操作为 k 次修改,每次修改可以选择一个数 hi 为 max(hi−p,0)。
每轮操作后每个 hi 将会被修改为 hi+ai。
你需要最小化最终 h1…n 中的最大值。
n≤105,m≤5×103,k≤10,1≤ai,p≤109,0≤hi≤109。
看到最小化最大值,考虑二分答案。
但是因为每次操作后,数都要和 0 取 max,所以很不好处理。
尝试把这个过程反过来,二分答案 H,则整个过程:
- 将每个 hi 修改为 hi−ai,但需要保证 hi≥ai。
- k 次修改,每次修改一个 hi 为 hi+p。
- 要求最终每个数不小于给定的 n 个数。
发现可以贪心。也就是,用一个堆维护“最可能减到 0 的数”(也就是按照 current heightai 排序),每天选取要变成 0 的那些数进行操作即可。
如果过程中出现了次数无法满足所有数 ≥0 的情况,则直接返回失败。否则将剩余的次数存起来。
最终检查剩余次数能否保证每个数大于等于给定的数即可。
时间复杂度 O((n+mk)lognlogw)。
#03 CF506E Mr. Kitayuta's Gift ⭐⭐⭐⭐⭐
给定一个小写字符串 s 和一个正整数 n。
要求在 s 中插入恰好 n 个小写字符使其回文的方案数。
|s|≤200,n≤109,答案对 104+7 取模。
首先考虑 n+|s| 为偶数的情况。
用 fi,l,r 表示只考虑回文串的前 i 个字符和后 i 个字符,它们与 s 尽可能匹配后,s 剩下 [l,r] 这段区间时的方案数。
用 gi 表示只考虑最终回文串的前 i 个和后 i 个字符,它们与 s 已经能够完全匹配时的方案数。
现在考虑转移:
1. 当前可加入一个字符使得 s 被完全匹配,即 r−l≤1,sl=sr。
gi+1←fi,l,rfi+1,l,r←25fi,l,r
2. 当前可加入一个字符,但 s 尚未完全匹配,即 r−l≥2,sl=sr
fi+1,l+1,r−1←fi,l,rfi+1,l,r←25fi,l,r
3. 当前不可加入一个字符使得两端同时匹配,即 sl≠sr
fi+1,l+1,r←fi,l,rfi+1,l,r−1←fi,l,rfi+1,l,r←24fi,l,r
4. 在此之前已经完全匹配了
gi+1←26gi
答案为 g(|s|+n)/2,当然,整个 DP 的过程满足矩阵乘法的条件,可以矩阵乘法优化。
但即便使用了矩阵乘法,这个 DP 的过程还是 O(|s|6log(n+|s|) 的,无法通过。
发现这个 DP 是一个在 DFA 上匹配的过程,例如 s= abaac 的转移过程如下:
红点对应 3 种情况,绿点对应第 1, 2 种情况。
考虑压缩这个自动机,考虑压缩这个自动机,可以发现,对于每一条从起点到终点的路径,如果上面有 k 个红点,那么就意味着有 ⌈|s|−k2⌉ 个绿点,同时最终连接终点的点一定是绿点。
更进一步的发现,所有红点个数相同的链,它们对答案的贡献是一样的,因此本质不同的链只有 O(|s|) 条。
红点对应 3 种情况,绿点对应第 1, 2 种情况。
考虑压缩这个自动机,考虑压缩这个自动机,可以发现,对于每一条从起点到终点的路径,如果上面有 k 个红点,那么就意味着有 ⌈|s|−k2⌉ 个绿点,同时最终连接终点的点一定是绿点。
更进一步的发现,所有红点个数相同的链,它们对答案的贡献是一样的,因此本质不同的链只有 O(|s|) 条。
现在尝试求出有 k 个红点的链的数量,设 hi,l,r 表示从起点到 [l,r] 对应的结点的路径中,有多少个红点,那么可以使用记忆化搜索在 O(|s|3) 的时间内求出答案。
求出了每种本质不同的链的数量后,可以对每条链做一次矩阵加速,时间复杂度降为 O(|s|4log(n+|s|))。
但这个时间复杂度依然无法通过,尝试构造一个结点数只有 O(|s|) 的自动机,方法如
压缩后的自动机结点数只有 O(|s|) 了,这时候再矩阵加速,时间复杂度就可以变成 O(|s|3log(n+|s|))。
可以利用矩阵的形式删掉一些不必要的转移稍微卡卡常数。
如果 n+|s| 为奇数,则最后一步转移只能增加一个字符。DFA 上区别在于,包含两个字符的绿点 → 终点且不走终点的自环的链是不合法的。那么去掉包含一个字符的点到终点的边,同时去掉终点的自环,得到的结果就是要去掉的方案数。
#04 CF512D Fox And Travelling ⭐⭐
给定一张 n 个点 m 条边的无向图。
一个点只有当与它直接相连的点中最多只有一个点未被选择过时才可被选择。
询问对于每个 0≤k≤n,有序选择 k 个点的方案数。
n≤100,m≤n(n−1)2,答案对 109+9 取模。
不妨考虑有哪些点可能会被删除。
容易发现,如果对于一个点 u,∃V,u∈V,且 V 的导出子图中不存在叶子结点,那么 u 就不可能被删除。
所以首先把这类点全部找到,剩下的点会构成若干个有根树和无根树,有根树的意思是根上是唯一一个不可以选择的点,因此必须从叶子往根方向选点。
对于有根树,设 fi,j 表示 i 子树中有序选 j 个点的方案数,那么就是树上背包,合并时需要乘一个组合数。
对于无根树,枚举它的根,以每个点为根做一次树上背包,这样发现每种选 i 个点的方案会被多计算 |tree|−i 次,那么除掉即可。
时间复杂度 O(n3),树形背包需要上下界优化。
#05 CF516D Drazil and Morning Exercise ⭐⭐⭐
给定一棵 n 个点的树,边有边权。
定义 fx=maxni=1dist(x,i)。
q 次询问最大的满足 maxx∈Sfx−minx∈Sfx≤l 的连通块 S 包含的点数。
n≤105,q≤50。
考虑带权直径的性质,可以发现,任取一条带权直径 s,t,则对于任意一个点 u,fu=max(dist(u,s),dist(u,t))。
所以 O(n) 的时间内就可以求出每一个点的 f。
fu 最小的 u 一定是某一个带权直径的中点,更进一步的,可以发现,以这个中点为根,这棵树的每一个结点的 f 值一定 ≥ 它的父亲的 f 值。
把所有结点按照 f 从大到小排序,对于每一次询问,枚举最小值 low,则答案就是所有 f∈[low,low+l] 的点形成的最大连通块大小。
于是使用双指针维护这个东西,因为父亲一定排在儿子后面,所以 r 指针往右扩展直接并查集合并,l 指针往右收缩直接将对应连通块的 size−1,因为删去的一定是叶子结点,所以必然不影响连通性。
时间复杂度 O(qnlogn)。
#06 CF516E Drazil and His Happy Friends ⭐⭐⭐⭐
有 n 个男生 m 个女生,编号分别为 0∼n−1 和 0∼m−1。
有 b 个男生和 g 个女生是快乐的,其他人是不快乐的。
在第 i 天,编号为 imodn 的男生和编号为 imodm 的女生会一起玩。
如果他们俩中有一个人是快乐的,则另一个人也会变快乐。
求至少要多少天所有人都会变快乐,或者判断不可能所有人都变快乐。
n,m≤109,b,g≤105。
令 d=gcd(m,n),可以发现,只有编号模 d 同余的男女才会在一起玩。
所以可以按照编号对 d 取模的余数划分出若干个子问题来求解。最终将子问题的答案取 max 即可。
注意到如果 d≥g+b,那么至少有一个子问题无解,直接特判掉这种情况。于是现在子问题的个数 ≤2×105。
考虑某一组,此时不妨设 n>m,同时有 gcd(n,m)=1。
先考虑最后一个变快乐的女生是什么时候。
设其为 i 号,在第 x 天变快乐,有 x≡i(modm)。
假设是因为 j 号男生变快乐的,那么有 x≡j(modn)。
如果 j 号男生一开始就是快乐的,那么他会在第 j 天让 jmodm 号女生变快乐,在第 j+n 天让 (j+n)modm 号女生变快乐,在第 j+cn 天让 (j+cn)modm 号女生变快乐。
令 c=x−jn,可以说,第 i 号女生是在 cn 天后,被第 jmodm 号女生变快乐的。
换一种表述方式即,如果 k 号女生变快乐了,那么在 cn 天后,第 (k+cn)modm 号女生一定会变快乐。
现在考虑同余最短路。
对每个女生 k,连一条 kn⟶((k+n)modm) 的边,表述如果 k 号女生在某一天变快乐了,n 天后 ((k+n)modm) 号女生也会变快乐。
对每个一开始就是快乐的男生 j,连一条 Sj⟶(jmodm) 的边,表示 j 号男生会在第 j 天,让 (jmodm) 号女生变快乐。
对每个一开始就是快乐的女生 i,连一条 Si⟶i 的边,表示从第 i 天起,这个女生每 n 天可以让另一个女生变快乐。
求出 S 到每一个点的最短路,答案是 S 到所有一开始不快乐的女生的最短路的长度的最大值。
但总点数还是 109 级别的,没法做。
注意到第一类边非常特点,它把所有的女生连成了一个大环。
所以只需要考虑第二、三类边的影响即可,第一类边的影响可以直接计算。
然后对男生同样如此处理一遍。
时间复杂度 O((b+g)log(b+g))。
#07 CF521D Shop ⭐
有 k 个正整数 a1⋯k。
有 n 个操作,每个操作给定正整数 i,b,有三种可能:
- 将 ai 赋值为 b
- 将 ai 加上 b
- 将 ai 乘以 b。
你可以从 n 个操作中选择最多 m 个操作,并按照一定顺序执行。
你的目标是最大化 ∏ki=1ai 的值。
k,n≤105。
首先发现,肯定是先赋值、再加法、最后乘法。
赋值可以转化成加法,但必须在加法前。
加法可以转化成乘法,不过必须按照从大到小贪心的转化,且加法也要在乘法之前。
一开始假设所有乘法操作都要选,如果乘法操作的个数多于 m 个,则去掉多出来贡献最小的。
对 k 个数上的加法操作进行排序,我们要从大到小贪心的选择,可以用 k 个指针维护。
用一个堆,每次取出贡献最大的加法操作,然后与贡献最小的乘法操作相比较。若加法操作的贡献更大,则去掉这个贡献最小的乘法操作,同时加入贡献最大的加法操作;否则说明此时达到最优解。
总时间复杂度为 O(nlogn)。
#08 CF521E Cycling City ⭐⭐
给定一张 n 个点 m 条边的无向简单图。
问图中能否找到两个点,满足这两个点之间有至少三条完全不相交的简单路径,如果可行,构造一组方案。
n,m≤2×105,图不保证连通。
三条不相交路径,意味着两个有交的环。
也就是说,有解的充要条件是,DFS 树上存在一条树边,被至少两条返祖边覆盖。
那么判定是否有解就非常简单了,可以直接树上差分。
考虑构造方案,设这条被多次覆盖的边为 ⟨u,v⟩,其中 u 是 v 的父亲,那么从 v 开始 DFS v 的子树,找到两条对应的返祖边,起点分别为 u1,u2,终点分别为 v1,v2。
那么答案的起点就是 LCA(u1,u2),终点就是 v1,直接把路径取出来即可。
时间复杂度 O(n)。
#09 CF526F Pudding Monsters ⭐
给定一个 n×n 的棋盘,其中有 n 个棋子,每行每列恰好有一个棋子。
求有多少个 k×k 的子棋盘中恰好有 k 个棋子。
n≤3×105。
问题等价于,对于一个排列 p,求有多少区间 [l,r] 满足 length−1=max−min。
使用扫描线扫描区间的右端点,用单调栈维护当前每个后缀的 max、min,然后用线段树维护当前每个后缀的 V=max−min−length 的值。
显然,合法的区间就是上面 V=−1 的区间。而实际上对于所有的区间都满足 V≥−1,所以线段树维护一下区间 Vmin 以及 Vmin 的个数即可。
时间复杂度 O(nlogn)。
#10 CF526G Spiders Evil Plan ⭐⭐⭐
给定一棵 n 个节点的无根树,每条边有边权。
有 q 次询问,每次询问给出 x,y,你需要选择 y 条树上的路径,使这些路径形成一个包含 x 的连通块,且连通块中包含的边权和最大。
n,q≤105,强制在线。
可以证明,使用 k 条路径可以覆盖一棵有 2k 个叶子的树。
所以当询问 y 时,连通块就是选择 2y 个叶子,让边权和尽可能大。
再考虑,每次询问中,一定存在一种方案使得直径的两端中至少有一端被选取。
那么我们以两个直径端点为根,每次询问在两棵树中分别查询即可。
那么,现在根是一个叶子(直径端点必然是叶子),且根必选。
也就是说,需要选其它至多 2y−1 个叶子,打通他们到根的链,并且最大化边权和。
发现这个和长链剖分的过程是等价的,贪心选取前 2y−1 长链即可。
但是选完以后不一定经过 x,所以需要做一下调整。
如果当前没经过 x,那么首先打通 x 的子树中最深的叶子到根的路径。
然后,要么是将贡献最小的长链去掉,要么是找到离 x 最近的长链将下半部分替换为 x 所在长链。
往上跳需要倍增,时间复杂度 O((n+q)logn)。
#11 CF527E Data Center Drama ⭐
给定一张 n 个点 m 条边无向图。
你需要加尽可能少的边,然后给所有边定向,使得每一个点的出入度都是偶数。
边可以是自环,也可以有重边。
n≤105,m≤2×105。
入度、出度均为偶数,即每个点的度数都是偶数,则这张无向图存在欧拉回路。
所以可以将总度数为奇数的点两两相连。
但是,还需要满足边数为偶数,所以如果边数不够的话,随便找一个点加一个自环即可。
然后跑一个欧拉回路出来,隔一条边换一个方向即可。
时间复杂度 O(n),注意跑欧拉回路一定要把用过的边删掉,否则会 TLE。
#12 CF536D Tavas in Kansas ⭐⭐⭐
给定一张 n 个点 m 条边的可能有自环和重边的无向连通图,每条边都有一个非负边权。
A 和 B 在这张图上玩一个游戏,在游戏中,第 i 个城市有一个权值 pi。
一开始,A 在城市 s 中,B 在城市 t 中,两人各有一个得分,初始为 0,A 为先手,然后轮流进行操作。
当轮到某一个人时,他必须选择一个非负整数 x,以选定所有与他所在的城市的最短距离不超过 x 的还未被选定过的城市,他的得分将会加上这些城市的权值。
另外,每个人每次必须能够至少选定一个城市。
当没有人可以选择时,游戏结束,得分高者获胜。
现在请你计算出,在两人都使用最佳策略的情况下,谁会获胜(或者判断为平局)。
n≤2×103,m≤105,|pi|≤109。
预处理 s,t 到每个点的最短路并离散化。
设 f(x,y,p) 表示当前剩下所有到 s 距离 ≥x,且到 t 距离 ≥y 的点,当前先手是 p=0/1,先手所能获得的最大分数。
记 cnt(x,y) 表示到 s 距离 ≥x,且到 t 距离 ≥y 的点的个数。
记 sum(x,y) 表示到 s 距离 ≥x,且到 t 距离 ≥y 的点权和。
有:
f(x,y,p)={0cnt(x,y)=0maxcnt(x′,y)<cnt(x,y){sum(x,y)−f(x′,y,1)}cnt(x,y)>0,p=0maxcnt(x,y′)<cnt(x,y){sum(x,y)−f(x,y′,0)}cnt(x,y)>0,p=1
使用前后缀和优化这个过程,可以做到 O(n2)。
#13 CF538G Berserk Robot ⭐⭐⭐⭐
有一个机器人,第 0 秒时在 (0,0) 位置。
机器人会循环执行一个长度为 l 的指令序列,每秒执行一个指令。
指令有 ULDR 四种,分别代表向上/左/下/右移动一格。
你不知道这个指令序列具体是什么,但是你知道 n 条信息,第 i 条信息为「第 ti 秒时机器人在 (xi,yi)」,保证 t 递增。
你需要构造一个满足这些信息的指令序列,或判断不存在。
n≤2×105,l≤2×106,ti,|xi|,|yi|≤1018。
上下左右不好坐,横纵坐标有关联。
考虑将坐标系逆时针旋转 45∘,同时扩大到原来的 √2 倍。
这样 ULDR 对应的就是 (1,1),(−1,1),(−1,−1),(1,−1),可以分开考虑横纵坐标了。
此时原来的 (x,y) 对应着 (x+y,y−x)。
但这样还是不够方便,考虑将 t 时刻的横纵坐标都 +t 再 /2。
这样 ULDR 对应的就是 (1,1),(0,1),(0,0),(1,0),此时原来的 (x,y) 对应成 (x+y+t2,y−x+t2)。
先判掉所有 2∤x+y+t 的情况,然后只用考虑距离上的约束。
设 si 表示 1∼i 时刻的位移,那么 (xi,yi)=sti=⌊til⌋sl+stimodl。设 pi=⌊til⌋,qi=timodl,则原式又等于 pisl+sqi。
将 x,y 分开考虑,不失一般性地讨论 x。
将所有二元组按照 q 从小到大排序,方便起见我们再引入两条新的信息 p=0,q=0,x=0,以及 p=−1,q=n,x=0。
考虑对于两条信息 (pi,qi,xi) 和 (pi+1,qi+1,xi+1),我们有 pisl+sqi=xi 以及 pi+1sl+sqi+1=xi+1,拿后一个等式减去前一个等式,可以得到 (pi+1−pi)sl+sqi+1−sqi=xi+1−xi,而 sqi+1−sqi∈[0,qi+1−qi],因此 (pi+1−pi)sl∈[xi+1−xi−(qi+1−qi),xi+1−xi]。
接下来分类讨论,求出 sl 的范围。记 Δx=xi+1−xi,Δp=pi+1−pi,Δq=qi+1−qi。
- 若 Δp=0,那么若 0∉[Δx−Δq,Δx],那么直接输出 NO,否则可以忽略该条件。
- 若 Δp>0,那么 sl∈[⌈Δx−ΔqΔp⌉,⌊ΔxΔp⌋]。
- 若 Δp<0,那么 sl∈[⌈ΔxΔp⌉,⌊Δx−ΔqΔp⌋]。
维护两个变量 L,R 表示 sl∈[L,R],一边扫描一边更新即可,如果最终 L>R 则输出 NO。
否则一定有解,不妨令 sl=L,并可以得到若干个 sqi+1−sqi=ri 的式子,显然根据之前的限制有 ri≤qi+1−qi,我们就令 qi+1∼qi+ri 步让 x 增加 1,qi+ri+1∼qi+1 步让 x 不变即可。
时间复杂度 O(nlogn)。
#14 CF538H Summer Dichotomy ⭐⭐⭐
有 T 名学生,你要从中选出至少 t 人,并将选出的人分成两组,可以有某一组是空的。
有 n 名老师,每名老师要被分配到两个小组之一,对于第 i 名老师,要求所在的小组中的学生人数 ∈[li,ri]。
此外,有 m 对老师不能在同一个小组中。
你需要判断能否满足所有要求,如果可以,请给出一种方案。
t≤T≤109,n,m≤105。
把所有 [li,ri] 看作数轴上的线段,先不考虑 t,T 的限制,可以证明,如果有解的话,n1=nmini=1ri,n2=nmaxi=1li 最优。
如果加上 t,T 的限制,可以发现,若 n1+n2<t,则只增大 n2 更优,若 n1+n2>T,则只减小 n1 更优。
因此可以直接求出最优的 n1,n2,最后二分图染色即可。
时间复杂度 O(n+m)。
#15 CF547D Mike and Fish ⭐
给定 n 个整点。
你要给每个点染成红色或蓝色。
要求同一水平线或垂直线上两种颜色的数量最多相差 1。
n,xi,yi≤2×105。
对于每个点,让横纵坐标之间连一条边。
对于一个代表横坐标的点:
- 每有一条边走出,就多一个红点。
- 每有一条边走入,就多一个蓝点。
对于一个代表纵坐标的点:
- 每有一条边走入,就多一个红点。
- 每有一条边走出,就多一个蓝点。
那么题意转化为对每条边定向,使得每个点的入度和出度最多相差 1。
由于度数为奇数的点一定有偶数个,不妨将他们全部向 0 连一条边,跑欧拉回路即可。
#16 CF547E Mike and Friends ⭐⭐
给定 n 个字符串 s1⋯n。
q 次询问 sk 在 sl⋯r 中出现了多少次。
n,∑|s|≤2×105,q≤5×105。
将询问差分为 sk 在 s1⋯r 中出现的次数减去 sk 在 s1⋯l−1 中出现的次数。
先对 n 个串建出 AC 自动机。
将字符串顺着扫一遍,对扫过的字符串在 AC 自动机上的所有结点打上 +1 标记。
当 s1⋯x 都打过标记后,可以回答所有「t 在 s1⋯x 中出现了多少次」这样的询问,询问的答案就是 sk 在 AC 自动机上的终点的 fail 树上的子树和。
按照 fail 树的 dfs 序建出树状数组维护即可,时间复杂度 O(nlogn)。
#17 CF549E Sasha Circle(计算几何)
给定平面上 n+m 个整点的坐标。
询问是否存在一个圆将前 n 个点和后 m 个点严格分开。
n,|x|,|y|≤104。
#18 CF553E Kyoya and Train(分治 FFT)
给定一张 n 个点 m 条边的无重边无自环的有向图,你要从 1 号点到 n 号点去。
如果你在 t 时刻之后到达 n 号点,你要交 x 元的罚款。
每条边从 ai 到 bi,走过它需要花费 ci 元,多次走过同一条边需要多次花费。
走过每条边所需的时间是随机的,对于 k∈[1,t],pi,k105 表示走过第 i 条边需要时间 k 的概率。因此如果多次走过同一条边,所需的时间也可能不同。
你希望花费尽可能少的钱(花费与罚款之和)到达 n 号点,因此每到达一个点,你可能会更改原有的计划。
求在最优决策下,你期望花费的钱数。
n≤50,m≤100,t≤2×104,x,ci≤106,∑tk=1pi,k=105,答案精度误差 ≤10−6。
#19 CF555E Case of Computer Network ⭐
给定一张 n 个点 m 条边的无向图。
给定 q 组有向点对 (s,t)。
询问是否存在使得所有 s 都能到达 t 的无向图中每条边的定向方案。
n,m,q≤2×105。
先把边双缩点,因为边双必然存在一种方案使得其中任意两点均可以互相到达。
因为边双缩点后图变成了一棵树,所以每个跨边双的限制就变成了一条树上路径的限制。
通过树上差分检验即可,时间复杂度 O(n)。
#20 CF559E Gerald and Path ⭐⭐
给定 n 条线段。
每条线段给定其中一端的位置及长度。
求所有线段覆盖的最大长度。
n≤100。
对所有的线段按照给定的端点的位置进行排序,然后考虑 DP。
用 fi,j,dir 表示前 i 条线段,所覆盖的最右边一段由线段 j 控制,j 的方向为 dir=0/1。
如果往右铺的话,转移是显然的,但如果往左铺,就会导致一个后缀的线段被完全覆盖,即不造成任何贡献,因此枚举上一个造成贡献的线段即可。
时间复杂度 O(n2) 或 O(n3)。
#21 CF566C Logistical Questions ⭐⭐⭐
一棵 n 个节点的树,点有点权,边有边权。
两点间的距离定义为两点间边权和的 32 次方。
求这棵树的带权重心。
n≤2×105。
设 d(x,i) 表示 dist(x,i)32,可以发现,当 x∈[a,b]([a,b] 表示一条链)时,d(x,i) 是一个下凸函数。
进一步,设 f(x)=∑ni=1d(x,i),因为凸函数的和还是凸函数,所以 f(x) 对于任意一条链也是一个下凸函数。
由此可以得到,整棵树有且仅有一个点 x 能取到 f(x) 的最小值,且从这个点向外 f(x) 逐渐变大。
考虑点分治,对于一个分治中心 x,先用 x 去更新答案,然后对所有子树的方向进行求导,必然只有一个方向的导数值是 <0 的,向那个方向走,继续更新答案即可。
时间复杂度 O(nlogn)。
#22 CF566E Restoring Map ⭐⭐⭐⭐
有一棵 n 个点的树,你不知道这棵树的边是怎么连的。
你得到了 n 条关于每个点信息,每条信息记录了距离某一个点 ≤2 的所有点。
但你不知道每条信息具体是哪个点的。
你需要构造一棵满足这些信息的树。
n≤103。
先考虑一般情况,即非叶结点个数大于等于 3。
不难发现两个非叶节点 u,v 有边,当且仅当存在两个集合的交仅含有两个元素 u,v,用 bitset 优化就可以 O(n3w) 得到所有非叶节点之间的边了。
找 1 的正确的写法是借用 _Find_first() 和 _Find_next() 函数,前者是找到 bitset 中从低位到高位第一个 1 的位置,后者是找到当前位置的下一个为 1 的位置,这样复杂度才会除以那个 w。
接下来考虑如何找到叶子节点在树中的父亲。
显然,对于每个叶子节点,在所有包含它的集合中,节点数最少的集合一定就是此叶子节点的集合。
因此我们可以确定每个叶子节点对应的集合是哪个。
如果我们把连边集合定义为一个非叶节点与和它相连的非叶节点构成的集合,可以发现,一个叶子节点的集合中去掉所有叶子节点,等于其父亲的连边集合。
那么我们就可以确定所有叶子节点的父亲了,同样可以 bitset 优化。
最后考虑非叶节点数量少于三个的情况。
如果不存在非叶节点,则 n=2,可以直接判掉。
如果只有一个非叶节点,那就意味着所有集合都是 {1,2,⋯n},也可以直接判掉。
如果有两个非叶节点,我们先采用至少三个非叶节点的方法找到这两个非叶节点,然后会发现这两个非叶节点的连边集合是一样的。但是,这个时候叶子的集合就只有两种,选其中一种里的叶子挂在一个非叶节点下,另一种里的叶子挂在另外一个非叶节点下就好了。
时间复杂度 O(n3w)。
#23 CF568C New Language ⭐⭐
将 a∼a+l−1 这 l 个字符分成 V,C 两个集合。
你需要构造一个长度为 n 的字符串:
- 满足 m 个限制,形如「若字符串的第 p1 个位置上的字符 ∈t1,则第 p2 个位置上的字符 ∈t2。(t1,t2∈{V,C})
- 字典序不小于另一个长度为 n 的字符串 s。
- 字典序尽可能小。
输出字符串,或判定无解。
l≤26,n≤200,m≤4n(n−1)。
限制长得很像 2-SAT 的样子,尝试用 2-SAT 去维护这个东西。
因为题目要求字典序最小,所以考虑贪心。
假如当前在考虑第 i 位,记 f=0/1 表示前 i−1 位是否和 s 卡满,用以确定第 i 位的字符的范围。
- 如果前 i 位确定后,后面出现了既必须为 V 又必须为 C 的位,则无解。
- 如果前 i 位确定后,前面仍然卡满 s,且后面无法满足字典序 ≥s,则无解。
对于第二种情况,具体地说,就是从 i 开始往后做“尽可能选大”的贪心,单次检验是 O(n) 的。
总时间复杂度 O(nm)。
#24 CF568E Longest Increasing Subsequence ⭐⭐⭐
给定一个长度为 n 的有 k 个空缺的序列。
你有 m 个数可以用于填补空缺。
要求最大化最长上升子序列的长度。
n,m≤105,k≤103。
由于多次填一个重复的数字不会对答案造成影响,所以姑且不讨论每个数字只能用一次的条件。
设 li,pi 分别表示在 i 不是空缺的位置时,1∼i 中包含 i 的最长上升子序列的长度和上一项的位置。
设 fi,gi 分别表示长度为 i 的上升子序列的最后一项的最小值和它所在的位置。
现在依次考虑每一个位置,设当前考虑的位置是 i。
若该位置不是空缺的,设该位置上的数为 x,那么可以在 f 上二分找到 <x 的最后一个位置 j,转移 li=j+1,pi=gj,fj+1=x,gj+1=i。
若该位置是空缺的,考虑从大到小枚举填补空缺的数,用一个指针 j 扫描 f 数组中 <x 的最大的 fj,然后依次更新 fj+1=x,gj+1=i,时间复杂度 O((n+m)k)。
求出答案长度后,考虑如何还原这个序列。
需要倒序还原,设已经还原了第 i 个数 x,在原序列中的位置是 j。
若这个位置不是空缺的,直接用 pj 找到上一项的位置。
若这个位置是空缺的,则现在它前面的不是空缺的位置中找到 s 满足 ls=i−1,同时 s 上的数 <x。如果找到了,那么上一项的位置就是 s,否则上一项的位置就是上一个空缺的位置,且这个空缺的位置填的数为可填的数中 <x 的最大的数。
对于还没有决策的空缺的位置,随便填上即可。
时间复杂度 O(nlogn+mlogm+(n+m)k)。
#25 CF571D Campus ⭐⭐
有一个长度为 n 的序列,初始全为 0。
有两类对下标的集合,初始时每一类各有 n 个集合,编号为 i 的集合里有下标 i。
一共有 m 个操作,操作有五种:
- U x y 将第一类编号为 y 的集合合并到编号为 x 的集合里。
- M x y 将第二类编号为 y 的集合合并到编号为 x 的集合里。
- A x 将第一类编号为 x 的集合中的所有下标在序列中对应的数加上 x 的集合大小。
- Z x 将第二类编号为 x 的集合中的所有下标在序列中对应的数设为 0。
- Q x 询问序列中下标为 x 的位置上的数。
n,m≤5×105。
如果我们能够利用 M 和 Z 操作求出对于每个询问的位置上次清零的时刻 t,那么这个询问的答案就应该是只保留 U 和 A 操作的情况下此时的值减去 t 时刻的值。
所以问题可以分为两步:
- 利用 M 和 Z 操作求出对于每个询问的位置上次清零的时刻 t。
- 利用 U 和 A 操作求出对于每个询问的位置当前和时刻 t 的值。
将询问离线。分别对 U 操作和 M 操作的合并过程建立两棵树,A 就相当于是子树加,Z 就相当于是子树赋值,直接使用线段树维护就好了。
时间复杂度 O(nlogn)。
#26 CF571E Geometric Progressions ⭐⭐⭐
给定 n 以及 n 个正整数对 ai,bi。
第 i 对 ai,bi 确定了一个序列 {ai,aibi,aib2i,aib3i,⋯}。
询问最小的在 n 个序列中都有出现的数,或者判断不存在。
n≤100,ai,bi≤109,答案对 109+7 取模。
分解质因数,用质数的指数来表示一个数字。
考虑每次对两个集合取交集,显然只会有 3 种情况分类讨论:
- 交集为空集:答案为 −1。
- 交集为一个数:只考虑这个数是不是在后面的集合中都存在就行了。
- 交集为一个集合:用一组 (a,b) 来表示这个集合。相当于是合并了两个集合。
如果没有出现前两种情况,合并 n−1 次以后,输出最后一个集合的 a 即可。
考虑合并的过程,对于一个质数 p,用 Vp(x) 表示 x 中 p 的次数。
对第 i 个集合的 ai,bi 质因数分解后,集合内的第 j 个数 si,j 满足 Vp(si,j)=Vp(ai)+(j−1)×Vp(bi)。
所以合并的时候,枚举质数 p,分类讨论:
- 两个集合的 Vp(b) 都 =0:直接判定两个集合的 Vp(a) 是否相等。
- 只有一个集合的 Vp(b)=0:那么交集的 p 的指数必然被确定了,合并就可以确定唯一的 j,相等于最终答案都取绝于了一个固定的数,直接判定这个数字可不可以成为答案即可。
- 两个集合的 Vp(b) 都 ≠0:相当于是对于所有的 p,形成了一个方程组:
Vp(ai)+x×Vp(bi)=Vp(aj)+y×Vp(bj)
移项后发现是关于 x,y 的二元一次方程组,删去重复的方程后,如果方程数 ≥2,那么要么能解出唯一解,要么无解,这种情况直接判掉就行。
如果只有一个方程,就需要用 exgcd 来解这个不定方程,得出 x 的最小非负整数解 x0,则交集就可以写成下面的形式:
Vp(a′)=Vp(ai)+x0×Vp(bi)Vp(b′)=lcm(Vp(bi),Vp(bj))
最终 a′ 作为答案即可。
时间复杂度 O(nlog2n)。
#27 CF573E Bear and Bowling ⭐⭐⭐⭐
给定一个长度为 n 的序列 a1⋯n。
你要求一个 a 的子序列 b1⋯m(可以为空),使得 ∑mi=1i×bi 的值最大。
n≤105,|ai|≤107。
考虑一个贪心:一开始选空集,每次选一个不在集合当中的数字加入集合,每次选择贡献最大的那个数字加入。当所有数字的贡献都 <0 时,结束贪心。
这个贪心是正确的,不会证明。
考虑如何快速维护这个贪心。
贡献可以写成 kiai+bi 的形式,其中 ki 为 i 之前被选择的位置数 +1,bi 表示 i 之后被选择的位置的 a 之和。
使用分块,块内用单调队列维护一个上凸壳(因为询问的 k 显然是单调递增的)。
对于每次最大的位置 p,先将 p 的贡献计入答案,然后删除 p(将 p 的贡献设为 −∞)。
对 p 之前的位置,给 bi 加上 ap,对于 p 之后的位置,给 ki 加上 1。
对于每一个整块,分别打一个关于 k,b 的标记,对于 p 所在的块,暴力重构即可。
时间复杂度 O(n√n)。
#28 CF575A Fibonotci ⭐
给定 s0,s1,⋯,sn−1,对于 i≥n,有 m 个 i 给定 si,剩下的 i 满足 si=simodn。
定义递推数列 f,f0=0,f1=1,对于 i≥2,fi=si−1fi−1+si−2fi−2。
求 fkmodp 的值。
n,m≤5×104,k≤1018,si,p≤109。
若不考虑 m 个特殊点,则直接求出 n 个的积,然后快速幂即可。
现在考虑特殊点,把含有特殊点的周期蓝出来单独算,用线段树支持单点修改矩阵,查询全局矩阵乘积即可。
时间复杂度 O(n+m(logk+logn))。
#29 CF575E Spectator Riots(计算几何)
给定整点集 S={(x,y)∣x,y∈[0,105]}。
给定另外 n 个整点集 P1⋯n,对于 1≤i≤n,给定 xi,yi,vi,Pi=S∩{(x,y)∣|x−xi|+|y−yi|∈[0,vi]}。
有 n 个整点 P1⋯n,对于 1≤i≤n,Pi 在 Pi 中等概率随机。
你需要从点集 ⋃ni=1Pi 中选择三个不共线的点,使这三个点的外接圆期望所覆盖(包括圆周上)的 P 点最多。如果有多种方案,则要求这个外接圆的半径最大。如果还有多种方案,任何一种都可以。
你求出的半径与答案的误差应 ≤0.01,答案的半径 ≤1010。
n≤105,(xi,yi)∈S 且不全都共线,vi≤103。
#30 CF575I Robots protection ⭐⭐⭐
你需要在平面直角坐标系上进行 q 次操作。
每次操作有两种,要么放置一个两条直角边平行于坐标轴的等腰直角三角形,要么查询某一个点被多少个三角形覆盖。
每个等腰直角三角形可以用四个参数 dir,x,y,len 确定,其中 dir∈[1,4] 表示三角形的方向,(x,y) 表示直角的顶点坐标,len 表示直角边的长度。
保证所有点的坐标都是整数且 ∈[1,n]。
n≤5×103,q≤105。
由于四种方向是对称的,只考虑直角顶点在左下角的情况。
令三个顶点为 (x,y),(x+l,y),(x,y+l)。
首先发现需要加的所有点 (x′,y′),都满足 x+y≤x′+y′≤x+y+l,这个东西可以用一棵树状数组维护。
然后我们就是要减去这两块:
我们考虑如何减去,观察这些点的性质,首先均满足 x′+y′∈[x+y,x+y+l],然后其还满足 x′<x 或 y′<y。于是我们可以考虑开两棵二维树状数组,一棵维护下标 (x+y,x),另一棵维护下标 (x+y,y),然后在这两棵树状数组上矩阵加即可。
时间复杂度 O(qlog2n)。
#31 CF576D Flights for Regular Customers ⭐⭐
给定一张 n 个点 m 条边的有向图。
一开始你在 1 号节点,你要走到 n 号节点去。
只有当你已经走过了至少 di 条边时,你才能走第 i 条边。
问最少要走多少条边,或判断无法到达。
n,m≤150,di≤109。
考虑在这张图上游走,所有的边一定是按 di 从小到大的顺序解锁。
假设此时加入的边的 d 值为 t,首先要求的是经过恰好 t 条边时可以到达哪些点。
可以使用矩阵乘法递推,因为矩阵的值只有 0/1,可以使用 bitset 优化。
当恰好加了一条边以后,在这个图上 BFS,即可求出当前的答案。
时间复杂度 O(n3mlogdw)。
#32 CF576E Painting Edges ⭐⭐⭐⭐
给定一张 n 个点 m 条边的无向图。
一共有 k 种颜色,一开始,每条边都没有颜色。
定义合法状态为仅保留染成 k 种颜色中的任何一种颜色的边,图都是一张二分图。
有 q 次操作,第 i 次操作将第 ei 条边的颜色染成 ci。
但并不是每次操作都会被执行,只有当执行后仍然合法,才会执行本次操作。
你需要判断每次操作是否会被执行。
n,m,q≤5×105,k≤50。
发现不弱于加边删边二分图判定,考虑线段树分治。
因为 k≤50,所以考虑对每一种颜色,开一个可撤销扩展域并查集。
对每一条边的两次相邻的染色 x,y,染色区间为 [x+1,y−1],颜色有两种可能:
染上去了,颜色是 x 染色时的颜色。
没染上去,颜色是上一次染色的颜色。
分治到一个 x 的时候,判定当前染色是否合法,然后就可以知道这次染色的颜色,再把染色区间加到线段树中即可。
时间复杂度 O(nk+nlog2n)。
#33 CF578E Walking! ⭐
给定一个长度为 n 的只包含 L, R 的字符串 s。
构造一个 n 排列 p 满足 spi≠spi+1 (1≤i<n)。
最小化 p 中 pi>pi+1 (1≤i<n) 的数量。
n≤105,数据保证有解。
问题等价于,将 s 划分成尽可能少的 L, R 交替出现的非连续子序列。
考虑贪心,每添加一个字符,就在前面划分好的子序列中找一个可以接到末尾的接进去,没有可以接的就新开一个子序列。
最终构造方案需要拼接子序列,考虑如果满足拼接后仍是 L, R 交替出现的这个性质。
将子序列按照开头和结尾分为 4 类:LL, LR, RL, RR。
能合并的先合并,最后如果只剩下 LR, RL 两种,发现没法拼接了,那么考虑它们的最后一个位置的大小关系,将末尾位置较大的子序列的末尾给末尾位置较小的子序列,这时候就变成了 LL, RR,可以合并了。
时间复杂度 O(n)。
#34 CF578F Mirror Box ⭐⭐⭐⭐⭐
在一个 n×m 的网格中,每个格子里都有一个呈 \ 或 / 状的镜子。
一个合法的网格需要满足从任意一个边界段垂直射进网格中,光线会从相邻的边界段射出,同时网格中的每一段都被至少一条光线穿透。
现在网格中有 k 个位置的镜子形状不确定,求有多少种合法的网格。
n,m≤100,答案对质数 p 取模。
将镜子转化为在 (n+1)×(m+1) 的点阵中连边,将点阵黑白染色,可以发现合法方案对应黑 / 白格子的生成树。
为什么是生成树呢?
如果有环,那必然有格子被封闭起来,则不满足每个网格线都存在一条光线穿透。
如果不连通,则就会存在光线无法从相邻的边界射出。
所以把已知的边连上,用并查集缩点,然后分别对黑点 / 白点使用矩阵树定理求一次生成树即可。这是因为当一种颜色形成生成树时,另一种颜色能连的边其实已经确定了。两次矩阵树定理的结果加起来就是答案。
时间复杂度 O(k3)。
#35 CF582D Number of Binominal Coefficients ⭐⭐⭐⭐
给定质数 p 和整数 α,A,求满足 0≤k≤n≤A 且 pα|(nk) 的数对 (n,k) 的个数。
p,α≤109,A<101000,答案对 109+7 取模。
库莫尔定理:(n+mm) 中质数 p 的幂次为 n 与 m 在 p 进制下相加时的进位次数。
于是可以数位 DP,用 fi,j,0/1,0/1 表示 p 进制下前 i 位,进位 j 次,当前是不是卡上界,后一位是否往前一位进位时的方案数。
转移的情况比较多,需要算一算可行填法,以保证复杂度与 p 无关。
时间复杂度 O(log2A)。
#36 CF582E Boolean Function(FWT)
A,B,C,D,a,b,c,d 为八个布尔变量,其中小写字母的值等于对应大写字母的值取反。
&,| 为两个布尔操作符。
布尔表达式为一个变量,或通过操作符连接起来的两个表达式。
布尔函数 f(A,B,C,D) 为一个布尔表达式。
给定一个可能缺少某些变量和操作符(用 ? 代替)的函数 s,并给出 n 个函数在 A,B,C,D 确定时的值。
求可能的函数个数。
|s|≤500,n≤16,答案对 109+7 取模。
#37 CF585E Present for Vitalik the Philatelist ⭐⭐
给定一个序列 a1⋯n,求有多少种方法选出一个子序列 S 和一个元素 x,使得元素不在子序列中,且 gcd(S)>1,gcd(x,S)=1。
n≤5×105,答案对 109+7 取模。
可以发现,当不满足第一个条件时,第二个条件一定会得到满足。
所以答案等于满足第二个条件的方案数减去不满足第一个条件的方案数。
先考虑如何求出 gcd(S)≠1 的方案数。记 cnti 表示能被 i 整除的数字的个数,那么方案数就等于 ∑i>1−μ(i)(2cnti−1)。
而 gcd(x,S)≠1 的集合的数量,就等于 ∑i>1,i|x−μ(i)(2cnti−1)。
数据范围下 μ(i)≠0 的只有 28−1=255 个(数据范围下 a 至多只有 8 个质因子),所以直接求复杂度是没问题的。
#38 CF585F Digits of Number Pi ⭐⭐⭐⭐
给定长度为 n 的数字串 s 和长度为 d 的不含前导零的数字串 x,y (x≤y)。
求存在长度至少为 ⌊d2⌋ 的子串是 s 的子串的数字串 t∈[x,y] 的数量。
n≤103,d≤50。
如果存在长度至少为 ⌊d2⌋ 的子串,那必然存在长度恰好为 ⌊d2⌋ 的子串。
把 s 所有长度为 ⌊d2⌋ 的子串拿出来建 AC 自动机。
显然 [x,y] 中的数字串可以差分为 [0,y]−[0,x−1]。
用 fi,j,0/1 表示现在考虑到第 i 位,在 AC 自动机的节点 j 上,当前是不是卡上界。
每次转移的时候枚举下一位上填的数字,转移到 AC 自动机上的对应结点即可。
时间复杂度 O(nd2)。
#39 CF587D Duff in Mafia ⭐⭐⭐⭐
给定一张 n 个点 m 条边的无向图,每条边有一个颜色 c 和权值 t。
你要选出一些边,使得它们是一个匹配,同时剩下的边每种颜色也是一个匹配。
同时,你要最小化选出的边的最大权值。
n,m≤5×104。
首先二分答案,所有 >mid 的边都不能选。
建立结点 xi 表示选第 i 条边,x′i 表示不选第 i 条边。
- 对于一定不能选的边,连边 xi→x′i。
- 对于同一个点 u 相连的两条边 i,j,连边 xi→x′j。
- 对于同一个点 u 相连的两条颜色相同的边 i,j,连边 x′i→xj。
这样连边的复杂度是 O(m2) 的,单次复杂度没法承受。
于是可以使用前缀优化,设 x1⋯k 的前缀点为 s1⋯k,x′1⋯k 的后缀点为 s′1⋯k。
这时候连边:
- xi→si,s′i→x′i
- si−1→si,s′i→s′i−1
- si−1→x′i,xi→s′i−1
容易发现这和第二类边是等价的,所以第三类边也可以类似地优化。
时间复杂度 O((n+m)logw)。
#40 CF587F Duff is Mad ⭐⭐⭐⭐
给定 n 个字符串 s1⋯n。
q 次询问 sl⋯r 在 sk 中出现了多少次。
记 m=n∑i=1|si|,n,q,m≤105。
对所有串建立 AC 自动机。
考虑根号分治,设置阈值 T。
对于 |sk|>T 的询问,因为这样的串不超过 O(mT) 个,可以对这样的询问 O(m) 处理。
即,扫描 AC 自动机中的每一个结点,处理出“当出现一个以该结点为末尾的串时,对答案的贡献”。然后将询问差分为 s1⋯r 在 sk 中的出现次数减去 s1⋯l−1 在 sk 中的出现次数,依次扫描每个串,每扫到一个串就加上对应的贡献。
这部分的时间复杂度为 O(m2T+qlogq)。
若 |sk|≤T,考虑对每个串 O(|sk|) 处理。
按顺序扫过 n 个串,每扫到一个串就将其最后一个节点的子树内的所有点的权值 +1,处理询问的时候直接暴力求。
时间复杂度 O(nlogm+qTlogm)。
这两种操作实际上相当于在 DFS 序上区间加和单点查,树状数组即可。
当 T 取 m√qlogm 时,最优时间复杂度为 O(nlogm+qlogq+m√qlogm)。
#41 CF590E Birthday ⭐⭐⭐⭐
给定 n 个仅包含 a, b 的字符串。
你需要去掉尽可能少的字符串,使得剩下的字符串中不存在某一个串是另一个串的子串。
n≤750,n∑i=1|si|≤107。
首先可以 O(∑|si|) 的时间建出 AC 自动机求出所有的子串关系。
注意到子串关系是一个偏序关系,只需要跳到最近的结尾,路径压缩即可。建出来的图是一个 DAG。
题目要求的是 DAG 的最长反链,通过 Dilworth 定理可知,也就是这个 DAG 的最小可重复链覆盖。
而最小可重复链覆盖可以在 O(n3) 传递闭包后转化为最小链覆盖。
最小链覆盖的大小 =n− 拆点二分图的最大匹配。
考虑构造方案,首先需要构造这个二分图的最大独立集 I。
从右部的非匹配点开始 DFS,从右往左只能走非匹配边,从左往右只能走匹配边,取左侧被 DFS 到的点和右侧没被 DFS 到的点,可以证明这些点构成一个最小点覆盖。
最大独立集为最小点覆盖的补集。
得到最大独立集后,选出所有 入点、出点 都在 I 中的点,它们构成一个最长反链。
时间复杂度 O(n3.5)。
#42 CF594E Cutting the Line(Lyndon 分解、扩展 KMP)
给定一个字符串 s 和一个正整数 k。
你可以将 s 分成至多 k 段,并将每一段翻转或者不翻转。
求最终能够得到的字典序最小的 s。
|s|≤5×106。
#43 CF603E Pastoral Oddities ⭐⭐⭐⭐
给定一张 n 个点的无向图,初始没有边。
依次加入 m 条带权的边,每次加入后询问是否存在一个边集,满足每个点的度数均为奇数。
若存在,则还需要最小化边集中的最大边权。
n≤105,m≤3×105。
每个点的度数均为奇数 ⇔ 图中每个连通块都包含偶数个结点。
考虑静态怎么做,可以将边按照权值从小到大排序,然后贪心用并查集连边即可。
发现在动态加边的过程中,答案保持单调不上升,所以可以考虑整体二分。
设当前在处理 [l,r] 内的边,答案在 [x,y] 中,且 [1,l) 中权值 <x 的都已经被加入了。现在尝试求出 ansmid,就可以分治到 [l,mid−1][ansmid,y] 和 [mid+1,r][x,ansmid]。
先将 [l,mid] 中边权 <x 的边加入,之后再从小到大加入权值在 [x,y] 之间,加入时间 ≤mid 的边,一旦满足条件就停止,此时最后加入的边的边权就是 ansmid。
往左区间分治的时候,要把权值 <ansmid 且出现时间 <l 的边加入,分治右区间的时候要把权值 <x 且出现时间 <mid+1 的边加入。
使用可撤销并查集维护,时间复杂度 O(mlogmlogn)。
#44 CF605E Intergalaxy Trips ⭐⭐
n 个点的有向完全图。
i→j 的边每天出现的概率均为 pi,j。
每天选择一条存在的出边走过去。
求最优策略下从 1 到 n 的期望天数。
n≤103。
用 Eu 表示从 u 走到 n 期望最少天数。
考虑 Eu 的计算,对于 Eu 的所有出边 ⟨u,v⟩,显然我们会往 Ev 最小的那个方向走。
转移为(注意要考虑自环):
Eu=n∑v=1Ev1−∏ni=1(1−pu,i)×pu,v×∏i,Ei<Ev(1−pu,i)
于是一遍 Dijkstra,对每一个点维护已更新决策的 ∏(1−pu,v) 即可。
时间复杂度 O(n2)。
#45 CF607E Cross Sum(计算几何)
在平面直角坐标系中,给定 n 条不同的直线,第 i 条直线为 y=aix+bi。
可重点集 I 为 n 条直线两两的交点,可重数集 D 为 I 中所有点与 (p,q) 的距离。
你需要求出 D 中前 m 小的数之和。
n≤5×104,m≤3×107,|p|,|q|,|ai|,|bi|≤103 且输入的整数值为实际值的 103 倍,答案精度误差 ≤106。
#46 CF611G New Year and Cake(计算几何)
给定一个 n 个顶点的严格凸多边形。
要求 n(n−3)2 个由对角线将多边形割成两个部分的面积差 ×2 之和。
n≤5×105,答案对 109+7 取模。
#47 CF611H New Year and Forgotten Tree ⭐⭐⭐
有一棵 n 个节点的树,节点编号为 1∼n。
记录这棵树的方式是记录下每条边连接的两点的编号。
现在,你不知道这些编号具体是多少,你只知道它们在十进制下的位数。
请你构造出一棵满足要求的树,或判断没有满足要求的树。
n≤2×105。
对每种位数选择一个关键点,可以发现,如果存在合法的树,一定存在一种情况,使得关键点构成一个连通块,其他点连向某一个关键点。
可以用 Prufer 序列啥的枚举关键点的连接方式,对于剩下的边 (x,y),按照位数分类。
相当于是一个二分图带权匹配:
- 左部点代表剩余的边,有 log2n 种。
- 右部点代表非关键点,有 logn 种。
对于边 (x,y),可以是 x 挂在 y 的关键点上,也可以是 y 挂在 x 的关键点上。
所以跑一遍网络流看看这个图的最大匹配满不满即可,有解的话直接根据残量网络构造。
#48 CF613E Puzzle Lover ⭐⭐⭐
给定一个 2×n 的矩阵,每个位置上有一个小写字母。
有一个长度为 k 的小写字符串 w,询问矩阵中有多少条有向路径满足以下条件:
- 路径上的字母连起来恰好为 w。
- 不多次经过同一个位置。
- 只能向上下左右四个方向走。
n,k≤2×103,答案对 109+7 取模。
考虑头尾不在同一列的情况,不妨设头在左尾在右,将 w 反转后再求一遍即可。
当头在左时,可以把路径分为三个部分。
- 从起点向左走然后绕回起点这一列的路径。
- 起点与终点所在列中间的路径
- 从终点向走右然后绕回终点这一列的路径。
首先考虑 1, 3 部分,枚举终点位置,然后哈希即可判断。
第 2 部分使用 dp 解决,用 fi,j,k 表示当前在 (i,j),匹配了 k 个字符,上一个所在的点是 (i,j−1),这时候的方案数。同理,用 gi,j,k 表表示上一个所在的点是 (3−i,j),这时候的方案数。
时间复杂度 O(n2)。
#49 CF626G Raffles ⭐
有 n 个奖池,第 i 个奖池的奖金是 pi,已经有 li 张彩票押在上面。
现在你有 t 张彩票,你需要将你的彩票分配到这些奖池中,并且保证你在每个奖池中押的彩票数不能超过该奖池原有的彩票数。
若你在第 i 个奖池中押了 ti 张彩票,则你中奖的概率为 titi+li,若你中奖,你可以获得这个奖池的全部奖金 pi。
一共有 q 次事件,每次事件会使某个 li 加 1 或减 1。
你需要在每个事件后求出在最佳方案下你获得的奖金总数的最大期望值。
n,t,q≤2×105,pi,li≤103,答案精度误差 ≤10−6。
注意到,对于某一个奖池来说,随着你押进去的彩票的增多,对答案的贡献会减少。
于是对于静态的情况,可以用一个堆维护再押一张彩票的贡献,每次取出贡献最大的计入答案。
时间复杂度 O((n+t)logn)。
当存在修改时,可以用 multiset 去维护当前方案,每当当前方案不是最优的方案时,就找当前方案中贡献最小的彩票换成另一个贡献最大的彩票。
这个东西的时间复杂度是对的,因为每次修改只会最多引起一张彩票的变化。
时间复杂度 O((n+t+q)logn)。
#50 CF627F Island Puzzle ⭐⭐⭐
给定一棵 n 个点的树,每个点上都有一个 [0,n−1] 的数,任意两点上的数都不同。
每次你可以交换 0 所在的点和与其相连的任一点上的数,同时你可以最多加入一条边。
给定目标状态,你需要在加入的边数尽量小的前提下,求出最少的步数,或者判断无法达成目标。
n≤2×105。
树上的话方案是唯一的,只要把 0 从 s 转到 t 看看是不是满足条件就行了。
考虑基环树的情况,可以发现,当 0 从某一个位置 p 进入环,走了一圈又回到 p 的话,所有环上除了 p 的点权值形成了一个循环,而转了若干次的话,权值形成一个轮换。
以 t 为根建树,则所有权值需要改变的点再加上 p,在树上应当呈现出一条路径。p 应当是这条路径的 LCA。
所以,如果无法找到这样的路径,或权值不构成一个轮换,则无解。
最后来最小化交换次数。
对于加入的一条边 ⟨u,v⟩,有两种旋转方法:u→v 和 v→u。分别计算取 min 即可。
假设从 u→v,这个轮换的循环次数最小为 c,则假设 s=t,可以得到一个解为 2⋅dist(t,p)+c⋅(dist(u,v)+1)。
但如果 s≠t 需要从 s 先移动到根,注意重复的路径要减掉。
时间复杂度 O(n)。
#51 CF627E Orchestra ⭐⭐⭐
在一个 r×c 的矩阵中有 n 个点,问有多少个连续子矩阵至少包含 k 个点。
r,c,n≤3×103,k≤10。
考虑只枚举上边界 u 和下边界 d,维护右端点分别为每一个列的时候的答案。
从下到上枚举下边界,对于一个右端点,找到它左边的第 k 个给定的点,这个点所在的列就是它对答案的贡献。
于是考虑将 u∼n 行的点拉出来按照列排序,建立双向链表,那么 d 往上推的过程就是不断在双向链表中删点的过程,同时它只会影响 k 个点的答案,所以可以用 O(k) 的时间去删除一个点。
时间复杂度 O(n2k)。
#52 CF639E Bear and Paradox ⭐
有 n 个问题,第 i 个问题的初始得分为 pi,所花费的时间为 ti。
设 T=n∑i=1ti,你可以按照某个顺序恰好花费 T 时间完成所有问题。
若你在时刻 x 完成了问题 i,你可以得到 pi⋅(1−cxT) 的得分,其中 c 是一个 [0,1] 的实数。
对于每个 c,都存在至少一个可以使得分最大的最佳做题顺序。
对于一个做题顺序,若出现了两个问题 i,j 满足 pi<pj 但 i 的得分严格大于 j 的得分,则认为这种做题顺序存在悖论。
你需要求出最大的 c,使得这个 c 对应的任意最佳做题顺序都不存在悖论。
n≤1.5×105,pi,ti≤108,答案精度误差 ≤10−6。
使用邻值交换法,可以证明,最优策略一定是按照 piti 降序的顺序做题。只有 piti 相同的那些题目是可以以随便的顺序去做。
所以,对于每一个问题可以求出它的最早处理时间和最晚处理时间。然后二分一个 c,对每个问题 i 判断存不存在另一个问题 j 满足 pj<pi 且 i 最晚完成的得分小于 j 最早完成的得分,存在就不合法,不存在就合法。
时间复杂度 O(nlogn)。
#53 CF639F Bear and Chemistry ⭐⭐⭐
给定一张 n 个点 m 条边的初始无向图。
q 次询问,每次询问给定一个点集 V 和边集 E。
你需要判断,将 E 中的边加入初始无向图之后,V 中任意两个点 x,y 是否都能在每条边至多经过一次的情况下从 x 到 y 再回到 x。
n,m,q,∑|V|,∑|E|≤3×105,强制在线。
每对点都可以绕一圈再回来,相当于是 V 都在同一个边双中。
先对原图建边双树,注意到 ∑|V| 并不大,可以对每次询问建虚树,再跑一遍 tarjan 即可。
时间复杂度 O(nlogn)。
#54 CF666D Chain Reaction(屑暴力题)
平面直角坐标系中有四个整点。
你可以将每个点水平或者垂直移动到一个整点,使得这四个点恰好成为一个平行于坐标轴的正方形的顶点(正方形不能退化成一个点)。
如果存在移动方案,则还要最小化对应点移动的最大距离。
t 组数据。
t≤50,|x|,|y|≤108。
#55 CF666E Forensic Examination ⭐⭐⭐
给定一个字符串 s,以及 m 个字符串 t1⋯m。
q 次询问,每次询问 s[pl:pr] 在字符串 tl…r 中的哪个串里作为子串出现的次数最多,如果有多个答案,输出最小的一个。
|s|,q≤5×105,m,m∑i=1|ti|≤5×104。
把 s 和所有 t 拼起来求 Height。
则一次询问 (pl,pr,l,r) 的答案就是 spl 对应的后缀的 Height 不小于 pr−pl+1 的区间中,每个对应 t 的后缀的下标在 [l,r] 中的众数。
可以把询问按照 pr−pl+1 离线后,在并查集上做线段树合并。
时间复杂度 O(nlogn)。
#56 CF671D Roads in Yusland ⭐⭐⭐⭐
给定一棵 n 个点的以 1 为根的树。
有 m 条路径 (x,y),保证 y 是 x 或 x 的祖先,每条路径有一个权值。
你要在这些路径中选择若干条路径,使它们能覆盖每条边,同时权值和最小。
n,m≤3×105。
用 f(u,i) 表示,覆盖了 u 的子树中所有的边,以及往上延伸到 dep=i 的位置,最小的代价。
用 g(u) 表示 dep(u)−1mini=1f(u,i),也就是至少覆盖了到 u 和父亲的边。
转移的时候,第一种情况是不选以 u 为起点的边:
f(u,i)=minv∈son(u){f(v,i)+∑w∈son(u),w≠vg(w)}=∑v∈son(u)g(v)+minv∈son(u){f(v,i)−g(v)}
另一种情况是选以 u 为起点的边:
f(u,depth)=∑v∈son(u)g(v)+cost
暴力 DP 的时间复杂度是 O(n2),考虑优化。
这个东西直接使用线段树合并是可以的,但不一定可以卡过 256MB 的空间限制。
对每一个点维护一个 set,里面存二元组 (i,f(u,i)),也就是 dp 数组中所有 ≠+∞ 的元素。
考虑转移时的操作,发现其实只需要全局加法,启发式合并,单点取 min,求全局 min。
最后一个不好维护,因为二元组在 set 里是按照第一关键字排序的,无法高效维护第二关键字的最小值,不过注意到,如果一个决策覆盖的比另一个决策短,代价还更大,它就没有存在的意义了。于是把这样的决策删除后,第二关键字就是单调下降的了,直接取 set 中的最后一个元素即可。
时间复杂度 O(nlog2n)。
当然还有另一种复杂度更优秀的做法。发现最终答案其实是 ∑u∈son(1)g(u),这提示我们是不是可以直接只维护 g,而不维护 f。
考虑转移,对每个结点维护一个小根堆。对于 v 的一种代价为 k 的决策,如何转移到 u 身上呢?
- 如果向上延伸超过了 u,那么在 u 的小根堆中,这种方案的权值应当为 k−g(v)+∑w∈son(u)g(w)。
- 如果向上延伸正好到了 u,那么不应该出现在 u 的小根堆中。
发现需要支持全局加,合并两个小根堆,使用左偏树即可。
时间复杂度 O(nlogn)。
#57 CF671E Organizing a Race(线段树维护单调栈)⭐⭐⭐⭐⭐
有 n 个点排成一行,第 i 个点与第 i+1 个点之间的距离为 wi 个单位。
每个点都有一个加油站,第 i 个点的加油站可以给你的车加能跑 gi 个单位的油。
若一辆初始没有油的车能从 l 一路向右开到 r,也能从 r 一路向左开到 l,则称 l,r 之间可以往返。
另外,你有 k 次将某个 gi 加 1 的机会。
请你求出在 l,r 之间可以往返的情况下,r−l+1 的最大值。
n≤105,k,wi,gi≤109。
#58 CF643D Bearish Fanpages ⭐⭐⭐
给定一个 n 个点的基环森林,第 i 个点与 fi 之间有一条边。
保证在任意时刻,这个基环森林中的环长至少为 3。
当一种「神秘事件」发生时,对于第 i 个点,设与其相邻的点(包括 fi 和 fj=i 的 j)的个数为 k,这 k 个点上都会出现 ⌊tik+1⌋ 个人,而 i 上会出现 ti−k⋅⌊tik+1⌋ 个人。
每次「神秘事件」发生都是互不影响的。
有 q 个操作,操作有三种。
- 1 i j:将 fi 改为 j,此操作不超过 5×104 个。
- 2 i:询问当「神秘事件」发生时,第 i 个点上出现的人数。
- 3:询问当「神秘事件」发生时,所有点上出现的人数的最小值和最大值。
n,q≤105,ti≤1012。
对每个点维护一个 multiset,用来求神秘事件发生时,第 i 个点上出现的人数。
全局再开一个 multiset,用来求所有点上出现的人数的最小值和最大值。
按照题意模拟即可。
时间复杂度 O((n+q)logn)。
#59 CF643F Bears and Juice ⭐⭐⭐⭐
有 n 只熊和若干桶果汁和恰好一桶酒,每一天每只熊会选择一些桶(可能不选)并各喝一杯,喝到酒的熊会去睡觉并不再回来,通过这个信息,熊们想知道哪个桶里是酒。
只有 p 个睡觉的位置,当睡觉的熊超过了 p 只或者所有熊都在睡觉时熊们就失败了。
令 Ri 表示在 i 天内桶的数量最多少,使得熊可以成功知道酒的位置。令 Xi=(i×Ri)mod232,你需要求出 X1⊕X2⊕…⊕Xq。
1≤n≤109,1≤p≤130,1≤q≤2×106。
我们把每一头熊什么时候睡觉写成一个长度为 n 的序列。
合法序列的数量为:
Ri=min{p,n−1}∑j=0(nj)ij
min{p,n−1} 表示实际有用的床的数量,因为熊不能同时去睡觉。
这个东西其实就是 q=i 时的答案了。
先考虑为什么。不妨给每个序列一个编号 i,表示如果最终情形是第 i 个序列,则编号 i 的桶里面是酒。
如果在第 k 个方案中,某一头熊始终没有睡觉,就一直不让这头熊喝第 k 桶酒。否则就在睡觉的那一天喝第 k 桶酒。
这样就形成了一一对应关系。
于是现在要计算:
q⨁i=1((i×Ri)mod232)=q⨁i=1((i(min{p,n−1}∑j=0(nj)ij))mod232)=q⨁i=1((min{p,n−1}∑j=0(nj)ij+1)mod232)
直接枚举 i,j 计算时间复杂度为 O(pq),可以接受,现在问题是如何求出 (nj)。
注意到 p 很小,考虑预处理出 (nk) (k≤min{p,n−1})。
对于 (nk)=n(n−1)(n−2)⋯(n−k+1)k!,暴力枚举上下的每一项,除以 gcd 进行约分,最终分母为 1,把分子乘起来即可。
时间复杂度 O(p3logp+pq)。
#60 CF643G Choosing Ads ⭐⭐
给定一个长度为 n 的序列和一个整数 p。
有 m 个操作,操作要么是区间赋值,要么是询问区间内出现次数至少占 p% 的数。
输出询问的答案时,可以包含错的数,也可以重复输出,但对的数一定要在答案中,且输出的数的个数不超过 ⌊100p⌋。
n,m≤1.5×105,20≤p≤100。
考虑当 p=51 的时候,其实就是求区间中的严格众数,一个经典的方法是维护一个擂台,每次新加入一个数,如果它和这个数相等,那么血量 +1,否则血量 −1,如果血量为 0 了就换成打掉它的这个数上擂台。
推广到 p=20 的情况,维护当前的 5 个众数和血量,每次新加入一个数,如果和这 5 个数的某个数相等,那么血量 +1,否则全部 −1,把血量为 0 的去掉后加入这个数,血量为 1。
搬到线段树上,合并的时候暴力把一边的 5 个数插入到另一边即可。这是因为,[l,r] 的众数不可能同时不为 [l,mid] 的众数和 [mid+1,r] 的众数。
时间复杂度 O(nk2logn),k=⌊100p⌋。
#61 CF679E Bear and Bad Powers of 42 ⭐⭐
定义一个正整数是坏的,当且仅当它是 42 的次幂,否则它是好的。
给定一个长度为 n 的序列 ai,保证初始时所有数都是好的。
有 q 次操作,每次操作有三种可能:
- 1 i 查询 ai。
- 2 l r x 将 al⋯r 赋值为一个好的数 x。
- 3 l r x 将 al⋯r 都加上 x,重复这一过程直到所有数都变好。
n,q≤105,ai,x≤109。
注意到在可能的值域内,42 的幂次并不多。
用线段树维护每个值到下一个 42 的幂次的差值。
在没有操作 2 的情况下,每个数最多被额外加 log42V 次,因此时间复杂度 O(nlognlog42V)。
有操作 2 时,整体打标记即可,时间复杂度不变。
#62 CF685C Optimal Point ⭐
立体直角坐标系中有 n 个整点。
求一个整点满足到这 n 个整点的曼哈顿距离的最大值最小。
n≤105。
很自然想到二分答案 d,可以列出一个不等式组。
|x−xi|+|y−yi|+|z−zi|≤d
对每个绝对值取正取负可以列出 23=8 个不等式。
合并这 8n 个不等式,得到一个不等式组。
{x+y+z∈[l0,r0]x+y−z∈[l1,r1]x−y+z∈[l2,r2]x−y−z∈[l3,r3]
设 a=x+y−z,b=x−y+z,c=x−y−z,则 a+b−c=x+y+z,这里隐含了 a≡b≡c(mod2),于是我们枚举 amod2,那么不等式组可以转化成关于 a,b,c 的不等式组,这个不等式组很好解。
时间复杂度 O(nlogx)。
#63 CF696F ...Dary!(计算几何)
给定一个 n 个点的严格凸多边形。
你要最小化 r,使得可以在这个多边形内或多边形上找到两个点,以它们为圆心以 r 为半径作两个圆,满足多边形的每条边所在的直线与至少一个圆有交点。
n≤300,答案精度误差 ≤10−6。
#64 CF698D Limak and Shooting Points ⭐
平面上有 k 个人和 n 个怪物,每个人手中有一支箭。
每支箭可以往任意方向射出,击中这个方向上的第一个怪物后,箭和怪物都会消失。
问有多少怪物可能会被击中。
k≤7,n≤103。
不同怪物之间是独立的,考虑每次检查怪物 x 能否被击中。
用全排列去枚举射击的顺序,不妨设为 p1,p2,⋯,pn。
钦定 p1 是最终去射杀 x 的,那么 p1 到 x 的路径上可能有别的障碍物 x′1,x′2,⋯,x′k,那么递归地令 p2 去射杀 x′1,如果路上还有障碍物就继续递归下去……单次检验是 O(k) 的。
时间复杂度 O(nk!k)。
#65 CF700E Cool Slogans ⭐⭐⭐⭐
给定一个字符串 S,要求构造字符串序列 s1,s2,…,sk,满足任意 si 都是 S 的子串,且任意 i∈[2,n],都有 si−1 在 si 中出现了至少 2 次(可以有重叠部分,只要起始、结尾位置不同即可)。
求可能的最大的 k 的值(即序列的最大可能长度)。
n≤2×105。
令 cool(s) 表示 s1=s,si+1 是 si 的 border 时,最大的 k 值。
那么答案就是 S 的所有子串的 cool 函数的最大值。
对 S 建 SA,令 fi 表示 Si 开头的后缀的所有前缀的最大 cool 值。
那么,从 fj=k−1 转移到 fi=k 的条件为:
- j>i;
- Sj 开头的后缀中存在一个前缀 t,满足 cool(t)=k−1 且 LCP(i,j)≥|t|。
所以再设 li 表示满足条件的 t 的最小长度。
那么转移的时候,已知 fi=k,如何求出 li 呢?
- k=1,则 li=1;
- 否则从所有 fj=k−1 (j>i) 的状态里找一个 l 最小的,记作 lmin,在 SA 中定位 LCP(i,x)≥lmin 的区间,用线段树求出这个区间中,在 i 之后且离 i 最近的位置 j,得到 li=lmin+j−i。
知道 fi 和 li 后,又可以用 i 去转移所有后继结点了。
时间复杂度 O(nlogn)。
#66 CF704B Ant Man ⭐⭐⭐⭐
有 n 个元素,第 i 个元素有五个参数 xi,ai,bi,ci,di。
你需要求出一个 1∼n 的排列 p,满足 p1=s,pn=e,同时最小化这个排列的权值。
一个排列的权值为 n−1∑i=1f(pi,pi+1),其中 f(i,j) 的值有两种情况:
- 若 i>j,则 f(i,j)=xi−xj+ci+bj。
- 若 i<j,则 f(i,j)=xj−xi+di+aj。
n≤5×103,s≠e,1≤x1<x2<⋯<xn≤109,1≤ai,bi,ci,di≤109。
考虑贪心,对 s→e 建立一个链表,每个元素的贡献只与他和左右两边的元素的相对大小关系有关。
考虑从小到大插入元素(先不考虑 s,e)每次插入一个元素 x 到 a→b 的中间时,即变为了 a→x→b,不妨设 x>a>b。
则原来的贡献有:
- a 往小
- 大往 b
现在的贡献有:
- a 往大
- 小往 x
- x 往小
- 大往 b
发现「大往 b」是不变的,且「小往 x」「x 往小」是定值,最终的问题就是把「a 往小」变成了「a 往大」。
同理,如果 x>b>a,那么就是把一个「小往 b」变成了「大往 b」。
可以发现,每次都是把一个和「小」有关的贡献变成和「大」有关。
于是每次贪心选最小值即可。
现在考虑上 s,e,把元素分为 [1,min(s,e)),(min(s,e),max(s,e)),(max(s,e),n] 三段。每一段都和上面是类似的。
时间复杂度 O(n2),但也可以 O(nlogn) 解决。
#67 CF704C Black Widow ⭐⭐
给定 m 个布尔变量 x1,x2,…,xm,以及 n 个形如 xi 或者 xi or xj 的布尔表达式,其中规定 x−i=¬xi。并且,保证 xi 和 x−i 在所有的布尔表达式中一共只会出现最多两次。
请你求出,在一共 2m 种布尔变量取值的情况下,有多少种情况,使得所有布尔表达式的值的异或为 1。此处认为,true 为 1,false 为 0。
由于结果可能过大,请输出答案模 109+7 的结果。
1≤n,m≤105。
对每个表达式建一个点,如果两个表达式含有相同的变量(xi 和 x−i 算相同的),那么就在这两个表达式之间连一条边。
显然每个点的度数 ≤2,那么不同连通块的表达式之间互相不影响,同一个连通块内,要么表达式形成了一条链,要么形成了一个环。
对每个连通块 i 求出有多少种方法使得其中的值异或和为 0/1,记作 ci,0,ci,1。
具体的方法是,对于链的连通块,用 fi,j,k (j,k=0/1) 表示考虑了前 i 个表达式,上一个变量的值取了 j,当前异或和是 k,这时候的方案数;对于环的连通块,随便找一个变量,暴力枚举它的值,然后断链为环即可。
求出 c 以后,对整张图以连通块为单位做一次 DP,这个 DP 是显然的。
时间复杂度 O(n)。
#68 CF704D Captain America ⭐⭐⭐
平面上有 n 个点,第 i 个点的坐标为 (xi,yi)。
每个点都要被涂色,涂成红色需要 r 元,涂成蓝色需要 b 元。
另外有 m 个限制,每个限制有两种可能:
- 1 l d 表示在直线 x=l 上,涂成两种颜色的点的数量之差不超过 d。
- 2 l d 表示在直线 y=l 上,涂成两种颜色的点的数量之差不超过 d。
要求构造出一种涂色方案使得满足所有限制且总花费最少,或判断无法构造。
n,m≤105。
不妨设 r≤b。对每个横坐标建一个点,对每个纵坐标建一个点,S 往所有横坐标连边,所有纵坐标往 T 连边,将每一个点的横坐标往纵坐标连一条边,容量为 [0,1],将涂红看作流。
对于一个限制 d,若这条线上的总的点数为 cnt,则红点的个数在 [⌈cnt−d2⌉,⌊cnt+d2⌋] 范围内,于是对应的点往 S/T 连的边设置这个流量范围。
求这个图的有源汇有上下界最大流即可,根据残量网络构造方案。
时间复杂度 O(n√n)。
#69 CF704E Iron Man ⭐⭐⭐⭐
给定一棵 n 个点的树。
有 m 个人,第 i 个人会在 ti 时刻出现在 vi,并以每时刻 ci 条边的速度向 ui 移动,到达 ui 立刻消失。出现的时段是左闭右闭的,因此如果 vi=ui,则在 ti 时刻 i 仍会出现。
求第一次有人相遇的时刻,或判断始终无人相遇。
相遇的时刻可以是实数。
n,m≤105,ti,ci≤104。
将这棵树剖分,将每条 ui→vi 的路径划分为 logn 条重链和 logn 条轻边,对每一个链分别考虑答案,取 min 即可。
以时间为横坐标,位置为纵坐标,每个人的路线都是一条线段,那么求出这些线段的交点中 x 最小的那个即可。
考虑使用扫描线扫描 x 轴,显然最小的那个交点一定是某时刻相邻的两条线段产生的。使用数据结构去维护线段,用相邻的交点去更新答案。这个数据结构需要支持:
- 插入一条线段
- 删除一条线段
- 求出相邻两个线段的交点
发现直接用 set 就行了。每条线段的权值是当前的纵坐标(开成和 t 相关的全局变量),当 t 后移的时候,因为一旦遇到了交点产生的时刻,就可以退出这个流程,所以不会发生 UB。
时间复杂度 O(nlog2n)。
注:set 中每个元素如果权重是一个全局变量,那么修改全局变量时,只要这些权重的相对顺序不改变,就没事,但要是相对顺序改变了就是 UB。
#70 CF708D Incorrect Flow ⭐⭐⭐
给定一张 n 个点 m 条边的网络,源点为 1,汇点为 n。
对于每条边,有容量 c,当前流量 f。
但这个图是错误的,可能存在 c<f,或者流量不守恒的情况。
你每次操作可以将某条边的 c 或 f 加 1 或减 1。
请你用最少的操作次数将图变成一个正确的网络。
n,m≤100,c,f≤106,1 没有入边,n 没有出边。
如果一条边最终流量不超过给定的 c,那么就不需要对这条边的 c 进行操作,否则 c 增大到最终的流量即可。
看到 n≤100,考虑网络流,对 f≤c 的边和 f>c 的边分开考虑,注意这里的边容量下界均为 0,下文「容量」指的是容量上界:
若 f≤c,分三种情况:
- 减小 f,连 v→u,容量 f,费用 1。
- 增大 f,但不超过 c,连 u→v,容量 c−f,费用 1。
- 增大 f,且超过 c,连 u→v,容量 +∞,费用 2。
若 f>c,首先将 f−c 的代价计入答案,然后分三种情况:
- 增加 f,连 u→v,容量 +∞,费用 2。
- 减少 f,但不低于 c,连 v→u,容量 f−c,费用 0。
- 减少 f,且低于 c,连 v→u,容量 c,费用 1。
对于初始的边,连 u→v,容量下界和上界均为 f,费用 0。
对于流量不平衡的点,用上下界网络流那套方法往超级源、汇连边即可。
于是这个问题就变成了无源汇上下界最小费用可行流,转化为 S→T 的最小费用最大流问题。
时间复杂度 O(n3)。
#71 CF708E Student's Camp ⭐⭐⭐⭐
有一个 (n+2)×m 的网格。
除了第一行和最后一行,其他每一行每一天最左边和最右边的格子都有 p 的概率消失。
求 k 天后,网格始终保持连通的概率。
n,m≤1.5×103,k≤105,答案对 109+7 取模。
问题等价于 k 天后相邻两行依然有交。
考虑 DP,用 f(i,l,r) 表示第 i 行剩下 [l,r],且前 i 行连通的概率。
设 D(i) 表示 k 天中吹掉一边的 i 个的概率,有:
D(i)=(ki)pi(1−p)k−i
可以 O(k) 预处理所有的 D(i)。
令 P(l,r)=D(l−1)D(m−r) 表示剩下 [l,r] 的概率,转移为:
f(i,l,r)=P(l,r)∑[l′,r′]∩[l,r]≠∅f(i−1,l′,r′)
边界是 f(0,1,m)=1,答案为 ∑f(n,l,r)。
暴力搞时间复杂度是 O(n5),需要优化。
考虑用全集减去不相交的,即要么 r′<l,要么 l′>r。
于是得到:
f(i,l,r)=P(l,r)[∑f(i−1,l′,r′)−∑r′<lf(i−1,l′,r′)−∑l′>rf(i−1,l′,r′)]
设 F(i),L(i,x),R(i,x) 分别代表三个求和号对应的内容,则:
f(i,l,r)=P(l,r)[F(i−1)−L(i−1,L)−R(i−1,r)]
答案为 F(n)。
用 SL(i,r) 表示 ∑l≤rf(i,l,r),即右端点为 r 的区间之和。
有 L(i,x)=∑r<xSL(i,r),这个可以直接前缀和。然后 R(i,x),F(i) 也可以类似地前缀和求出来。
时间复杂度 O(n3),瓶颈变成了 f 的状态数。
尝试直接不维护 f,将 DP 变成关于以上几个量之间的转移。
现在把 SL 表示为与 f 无关的形式:
SL(i,r)=∑l≤rf(i,l,r)=∑l≤rP(l,r)[F(i−1)−L(i−1,l)−R(i−1,r)]=D(m−r)∑l≤rD(l−1)[F(i−1)−L(i−1,l)−R(i−1,r)]=D(m−r)([F(i−1)−R(i−1,r)]∑l≤rD(l−1)−∑l≤rD(l−1)L(i−1,l))
再维护几个前缀和即可,时间复杂度 O(nm+k)。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探