【S-C1】是啥意思??
01. CF1858E2 Rollbacks (Hard Version)
维护一个初始为空的序列 a a a,支持以下操作:
- + x \texttt{+ }x + x:在序列末端插入 x x x;
- - k \texttt{- }k - k:在序列末端删除 k k k 个数( k k k 不超过当前序列长度);
- ? \texttt{?} ?:查询序列中不同的数字个数;
- ! \texttt{!} !:撤回前一个 + / - \texttt +/\texttt - +/- 操作。
有 q q q 次操作,强制在线, 1 ≤ q , x ≤ 10 6 1\le q,x\le 10^6 1≤q,x≤106,询问操作不超过 10 5 10^5 105。
解法
垃圾 *2600。
经典地,我们用 set 维护所有数字的出现的所有位置,更新时只需要查询其首位即可。
这样我们可以轻松实现 + \texttt + + 操作。
为了实现 - \texttt - - 操作,我们引入序列 A A A,使得序列 A A A 的前 l l l 位恰好为序列 a a a( l l l 为序列 a a a 此时的长度)。这样一来,我们更新时直接将 l l l 更改为 l − k l-k l−k 即可。
这样做同样是为了方便进行 ! \texttt ! ! 操作。因为我们实际上保留了 1 ∼ l max 1\sim l_{\max} 1∼lmax 的所有信息,足以进行回溯。
对于 ! \texttt ! ! 操作,我们使用 stack 存储所有操作,并尝试逆向地进行还原,具体情况与上面的 + / - \texttt +/\texttt - +/- 操作思路一致。
特别地,对于 + \texttt + + 操作,我们需要存储原来的 A l ′ A_{l'} Al′ 而不是 x x x。这是容易理解的。
至于答案的更新,我们在所有元素第一次出现的位置标记为 1 1 1,这个是已经维护过的。
那么 ? \texttt ? ? 操作只需要输出该数组在 [ 1 , l ] [1,l] [1,l] 上的区间和即可。
至此,我们需要一个可以支持单点修改、查询区间和的数据结构。拉一个树状数组即可。
时间复杂度 O ( q log q ) O(q\log q) O(qlogq)。
https://codeforces.com/contest/1858/submission/219045104
考虑优化,逐个解决瓶颈:
- 树状数组:可以用前缀和替代。容易发现是可行的;
- 维护各个元素出现的位置:我们发现改变一个元素第一次出现的位置,必然伴随着一个当前已知位置该元素的更新或该元素的彻底删除。据此可以只用一个数组 p o s pos pos 代替上述题解中提出的 set 进行维护。
据此,我们得到时间复杂度 O ( q ) O(q) O(q) 的做法。代码从略。
02. CF1804F Approximate Diameter
给定一个 n n n 个点 m m m 条边的初始无向图,有 q q q 次更新,每次更新向图中添加一条边。设 d ( G i ) d(G_i) d(Gi) 代表加入 i i i 条边后的图中两点之间的最大距离,你需要输出 q + 1 q+1 q+1 个整数 a 0 , a 1 , … , a q a_0,a_1,\dots,a_q a0,a1,…,aq,满足 ⌈ d ( G i ) 2 ⌉ ≤ a i ≤ 2 ⋅ d ( G i ) \Bigl\lceil\dfrac{d(G_i)}{2}\Bigr\rceil\le a_i\le 2\cdot d(G_i) ⌈2d(Gi)⌉≤ai≤2⋅d(Gi)。
n , m , q ≤ 10 5 n,m,q\le 10^5 n,m,q≤105,图连通。
解法
牛逼 *2700。
考虑一个性质,以某个点为端点的最长路径长度 s s s 满足
⌈ d ( G i ) 2 ⌉ ≤ s ≤ d ( G i ) \Bigl\lceil\dfrac{d(G_i)}2\Bigr\rceil\le s\le d(G_i) ⌈2d(Gi)⌉≤s≤d(Gi)
证明从略。
但是发现这个比要求的更紧。考虑怎么利用这个 2 ⋅ d ( G i ) 2\cdot d(G_i) 2⋅d(Gi)。
显然地,我们考虑二分某个答案什么时候失效,此时我们将该答案除以 2 2 2 即可。这是可行的,因为这个一眼单调。
二分枚举端点再套枚举答案即可,时间复杂度 O ( n log 2 n ) O(n\log^2 n) O(nlog2n)。
https://codeforces.com/contest/1804/submission/219393324
注意我们钦点的 dijkstra 算法别写丑,不然无法通过。
03. CF992E Nastya and King-Shamans
给定序列 a a a,维护两种操作:
- 单点将 a i → x a_i\to x ai→x;
- 查询 ∑ i = 1 n [ ( ∑ j = 1 i − 1 a j ) = a i ] \sum_{i=1}^n\Bigl[\Bigl(\sum_{j=1}^{i-1}a_j\Bigr)=a_i\Bigr] ∑i=1n[(∑j=1i−1aj)=ai]。
1 ≤ n , q ≤ 2 × 10 5 1\le n,q\le 2\times10^5 1≤n,q≤2×105, 0 ≤ a ≤ 10 9 0\le a\le 10^9 0≤a≤109。
解法
还不错的 *2500。
考虑一个性质:答案最多为 log n \log n logn。
证明从略。我们考虑直接拉线段树维护然后暴力遍历即可找到答案。
时间复杂度 O ( q log 2 n ) O(q\log^2 n) O(qlog2n)。
https://codeforces.com/contest/992/submission/219414380
04. CF825G Tree Queries
一棵树有 n n n 个节点,初始均为白色,有两种操作:
- 1 x \texttt{1 } x 1 x:把节点 x x x 染为黑色;
- 2 x \texttt{2 } x 2 x:查询 x x x 到树上任意一个黑色节点的简单路径上的编号最小的节点的编号。
保证第一个操作为染色操作,强制在线。 3 ≤ n ≤ 10 6 3\le n\le 10^6 3≤n≤106, 1 ≤ q ≤ 10 6 1\le q\le 10^6 1≤q≤106。
解法
小清新 *2500!
首先,显然地,为了方便维护,我们以第一次染色的节点 t t t 为根 dfs 一遍以求出所有节点到 t t t 的简单路径上的编号最小的节点的编号,即数组 a a a。
然后画个图可以理解:
- 对于染色操作,将目前维护的一个答案 a n s ← min ( a n s , a x ) ans\gets \min(ans,a_x) ans←min(ans,ax),可以证明这是正确的;
- 对于询问操作,我们输出 min ( a n s , a x ) \min(ans,a_x) min(ans,ax) 即可。
这是因为,我们的对于不同 t t t 的子树间的路径 u → v u\to v u→v,有 u → t → v u\to t\to v u→t→v 即为其简单路径。而对于子树内的路径,可以用 u → t , v → t u\to t,v\to t u→t,v→t 覆盖整个路径。
至此问题得到 O ( n ) O(n) O(n) 解决。
https://codeforces.com/contest/825/submission/219512635
05. CF1503D Flip the Cards
你有 n n n 张牌,第 i i i 张牌的正面有整数 a i a_i ai,背面有整数 b i b_i bi。所有 1 1 1 到 2 n 2n 2n 的整数都出现过正好一次。
我们认为这 n n n 张牌是好的当且仅当 a i a_i ai 升序, b i b_i bi 降序。
可以进行下面的操作:
- 交换 a i , b i a_i,b_i ai,bi。
- 随意重排这 n n n 张牌。
求如果要使这 n n n 张牌变成好的最少需要翻几次牌,或报告无解。
解法
牛逼 *2600。可惜放了 log \log log 过。
我们考虑到,若存在一个 i i i 使得 a i , b i ≤ n a_i,b_i\le n ai,bi≤n,则必然无解。
于是考虑将所有牌变成 a i < b i a_i<b_i ai<bi 的情况,则必然有 a i ≤ n , b i > n a_i\le n,b_i>n ai≤n,bi>n。于是设 f ( a i ) = b i f(a_i)=b_i f(ai)=bi。
下面研究 f ( i ) f(i) f(i)。发现当且仅当 f ( 1 … n ) f(1\ldots n) f(1…n) 可以被分为两个单调递减子序列使有解。
在 min j = 1 i { a j } > max j = i + 1 n { a j } \min_{j=1}^i\{a_j\}>\max_{j=i+1}^n\{a_j\} minj=1i{aj}>maxj=i+1n{aj} 处断点分段处理最小值即可。
时间复杂度 O ( n ) O(n) O(n),远超 log \log log 且更巧妙。
同时注意到没必要管顺序。
https://codeforces.com/contest/1503/submission/219536981
06. CF1646F Playing Around the Table
有 n n n 个人坐成一个圈,每个人手上有 n n n 张麻将,麻将上是 1 1 1 萬到 n n n 萬,每次可以让每个人同时掏出一张麻将给下一个人,构造一组方案使得第 i i i 个人能够做成「 i i i 萬一色」。
要求,操作次数不超过 n 2 − n n^2-n n2−n; 1 ≤ n ≤ 100 1\le n\le 100 1≤n≤100。
解法
萌萌 *2900。
我们考虑到,为了方便处理,设计一个过渡态「一气通贯」使所有情况达到统一。
可以证明,初态 → \to →「一气通贯」 → \to →「 i i i 萬一色」这一变换中,第一步的操作次数不超过 n ( n − 1 ) / 2 n(n-1)/2 n(n−1)/2,第二步的操作次数为 n ( n − 1 ) / 2 n(n-1)/2 n(n−1)/2。
下面,我们证明第一个。发现离「一气通贯」最远的状态是每个人均有一个「 j j j 萬一色」,证毕。
https://codeforces.com/contest/1646/submission/219623330
感觉还是比较难想的,所以场上才仅 3 人通过。
07. CF802H Fake News (medium)
构造字符串 s , p s,p s,p,使字符串 s s s 的为 p p p 的子串恰有 n ( 1 ≤ n ≤ 10 6 ) n\ (1\le n\le 10^6) n (1≤n≤106) 个。
解法
萌萌 *2200!感觉思路比较牛逼。
我首先想到了 CF1368B Codeforces Subsequences,不同的是,这道题是至少 n n n 个。
一个朴素的想法是,对于恰好有 k k k 个子串的情况 ( s , p ) (s,p) (s,p),我们可以实现 k → 2 k k\to 2 k k→2k。
具体地,任取一个新字符 c c c,令 s ′ = s c c s'=scc s′=scc, p ′ = p c p'=pc p′=pc 即可(这里直接用字符串拼接表示了)。
但是我们不能实现 k → k + 1 k\to k+1 k→k+1。这是很困难的。否则我们可以直接二进制拆分 n n n 解决。
考虑另一个思路,假设对于恰好有 k k k 个子串的情况 ( s , p ) (s,p) (s,p), s s s 可以被表示为 p u pu pu( u u u 也是一个字符串),任取一个新字符 c c c,那么我们可以实现
- k → 2 k + 1 k\to 2 k+1 k→2k+1:令 s ′ = p c u c c s'=pcucc s′=pcucc, p ′ = p c p'=pc p′=pc 即可;
- k → 2 k + 2 k\to 2 k+2 k→2k+2:令 s ′ = p c c u c c s'=pccucc s′=pccucc, p ′ = p c p'=pc p′=pc 即可。
这之后我们均直接可以更新 u ′ u' u′。
于是我们递归地解决这个问题即可。考虑每次处理 x x x 时,先解决 ⌊ x − 1 2 ⌋ \left\lfloor\frac{x-1}2\right\rfloor ⌊2x−1⌋ 时的情况,再回溯解决。容易发现这是合理的。
边界是 x = 1 , 2 x=1,2 x=1,2。这个也是平凡的,只需要使 p = a p=\texttt a p=a 即可。
这个是很对的,不考虑 string 类的复杂度是 O ( log n ) O(\log n) O(logn)。由于 2 26 > 10 6 2^{26}>10^6 226>106,我们可以仅用小写字母解决本题。
https://codeforces.com/contest/802/submission/219735685
08. CF1363F Rotating Substrings
给定两个长度为 n n n 的字符串 s , t s,t s,t。定义一次操作为选择 s s s 的一个子串 s l , l + 1 , … , r s_{l, l +1, \dots, r} sl,l+1,…,r,然后将其修改为 s r , l , l + 1 , l + 2 , … , r − 1 s_{r, l, l + 1, l + 2, \dots, r - 1 } sr,l,l+1,l+2,…,r−1。请求出使 s s s 与 t t t 相等的最小操作次数或判定无解。
多组数据, ∑ n ≤ 2000 \sum n \leq 2000 ∑n≤2000, s , t s, t s,t 中只有小写字母。
解法
很好 *2600。
我们考虑设 d p i , j dp_{i,j} dpi,j 表示 s s s 长度为 i i i 的前缀插入 i i i 后的若干个字符后,等于 t t t 长度为 j j j 的前缀的最小花费。显然这里有 i ≤ j i\le j i≤j。我们分情况转移:
- 如果 s i = t j s_i=t_j si=tj,可以直接匹配,也即 d p i , j = d p i − 1 , j − 1 dp_{i,j}=dp_{i-1,j-1} dpi,j=dpi−1,j−1;
- 如果 s r + 1 , n s_{r+1,n} sr+1,n 中存在 t j t_j tj,我们可以直接拉过来匹配,也即 d p i , j = d p i , j − 1 dp_{i,j}=dp_{i,j-1} dpi,j=dpi,j−1。我们这里暂时不计算贡献,具体原因见下;
- 直接把 s i s_i si 拉到前面去,也即 d p i , j = d p i − 1 , j + 1 dp_{i,j}=dp_{i-1,j}+1 dpi,j=dpi−1,j+1。这样的目的在于,我们保证了 2 中必定将会有某个 t j t_j tj 被拉到前面去并计算了其贡献。
于是就可以转移了。
感觉这个假借字符的思路比较巧妙。

被折叠的 条评论
为什么被折叠?



