Loading

2024 秋冬做题记录

题单


字符串专区

无特殊说明就是字符集为小写字母。


CF587F Duff is Mad

给定 \(n\) 个字符串 \(s_{1 \dots n}\)

\(q\) 次询问 \(s_{l \dots r}\)\(s_k\) 中出现次数之和。

\(n,q,\sum_{i=1}^n |s_i| \le 10^5\)

建 AC 自动机,计算 \(s_i\)\(s_j\) 中出现次数:

  • \(s_j\) 对应的 AC 自动机节点权值 \(+1\)

  • \(s_i\)\(s_j\) 中出现次数相当于 \(s_i\) 的结尾对应的节点 \(endp_i\) 的 fail 树子树权值和。

根号分治 \(|s_k|\),设置阈值 \(B\)

  • \(|s_k|>B\),将 \(s_k\) 对应的 AC 自动机节点权值 \(+1\),处理出 \(f_i\)\(endp_i\) 的 fail 树子树权值和,处理前缀和查询 \(\sum\limits_{i=l}^r f_i\)
  • \(|s_k|\le B\),我们转换思路,将 \(endp_i\) 的 fail 树子树加,查询 \(s_k\) 对应的 AC 自动机节点权值和,拍扁 dfn 用 BIT 维护,扫描线处理询问。

复杂度分析默认 \(L=\sum|s_i|\)\(n\) 同阶。

第一部分复杂度 \(O(\dfrac{n^2}{B})\),第二部分复杂度 \(O(nB\log n)\),取 \(B=\sqrt{n\log n}\),复杂度 \(O(n\sqrt{n\log n})\)

但你发现这实在太蠢了,第二部分 \(O(n)\) 次区间加,\(O(nB)\) 次区间查,改用分块平衡到 \(O(n\sqrt n+nB)\)

这时候就可以取 \(B=\sqrt n\),时间复杂度 \(O(n\sqrt n)\)

AC Record

upd:之前那发分块写错了,但是


inline void mdf(int l,int r){
    for(int i=l;i<=r;i++)
    {
        val[i]++;
    }
    return ;
}

(忘记删暴力了)直接就过了???CF 数据强度呢?

New AC Record

但是分块比暴力跑得慢……


CF1483F Exam

给定互不相同的字符串 \(s_1, s_2, \cdots, s_n\),求有多少对 \((i, j)\) 满足:

  • \(i \neq j\)
  • \(s_j\)\(s_i\) 的子串。
  • 不存在 \(k\) \((k \neq i, k \neq j)\) 满足 \(s_j\)\(s_k\) 的子串且 \(s_k\)\(s_i\) 的子串。

\(n,\sum \lvert s_i \rvert \leq 10^6\)

建 AC 自动机,枚举串 \(s_i\),统计 \(s_j\) 的数量。

对于 \(s_i\) 的某个前缀 \(s_i[1\dots p]\),它的后缀能匹配很多个 \(s_j\),然后只有这些 \(s_j\) 种最长的才可能合法。

考虑如何找到 \(s_i[1\dots p]\) 的后缀能匹配的最长 \(s_j\)。设 \(s_i[1\dots p]\) 在 fail 树上的节点是 \(x\)\(s_i[1\dots p]\) 能匹配 \(s_j\) 当且仅当 \(endp_j\)\(s_j\) 的结尾对应的节点)是 \(x\) 的祖先(fail 树上)。

那么最长的 \(s_j\) 即为最深的 \(endp_j\),于是可以 dfs 一遍预处理 fail 树上每个节点的最深 \(endp\) 祖先。

这里有一个细节,就是你 \(s_i\) 整个串(长度为 \(|s_i|\) 的前缀)选出来的 \(j=i\),应该为 fail 树上 \(endp_i\) 的不是它本身的最深 \(endp\) 祖先。

但是这样求出的 \(j\) 不一定满足第三条限制。可能 \(s_j\)\(s_i[1\dots p]\) 的的最长匹配后缀,但存在 \(s_k\)\(s_i[1\dots q]\) 的的最长匹配后缀并且 \(q-|s_k|+1\le p-|s_j|+1\),此时 \(s_k\) 包含 \(s_j\)

这个其实比较好解决,把 \(p\) 从大到小扫,记录当前最左的 \(p-|s_j|+1\)

好了这样我们就能统计出每个 \(s_j\)\(s_i\) 中,不被其他 \(s_k\) 覆盖地出现的次数了。

只需要判定这个次数是否等于 \(s_j\)\(s_i\) 中出现的总次数即可,这个在 fail 树上单点加子树查,拍扁 dfn 用 BIT 维护。

\(L=\sum|s_i|\),复杂度 \(O(L\log L)\)

AC Record


P8571 [JRKSJ R6] Dedicatus545

给定 \(n\) 个字符串 \(s_{1 \dots n}\)

\(q\) 次询问 \(s_{l \dots r}\)\(s_k\) 中出现次数的最大值。

\(1\le n,q \le 10^5\)\(1\le\sum_{i=1}^n|s_i|\le 5\times10^5\)

是不是很熟悉,CF587F Duff is Mad 求和变最大值。

再次考虑根号分治:

\(|s_k|>B\),将 \(s_k\) 对应的 AC 自动机节点权值 \(+1\),处理出 \(f_i\)\(endp_i\) 的 fail 树子树权值和,线段树维护 \(f_i\),查询 \(\max\limits_{i=l}^r f_i\)

\(|s_k|\le B\),将 \(s_k\) 对应的 AC 自动机节点权值 \(+1\),查询 \(s_i\)\(s_k\) 中的出现次数时为 \(endp_i\) 的子树和。

\(s_k\) 对应的 AC 自动机节点在 fail 树上建虚树,\(endp_i\) 的子树和必然等于虚树上某一节点的子树和。

考虑查询 \(l,r\) 时枚举这个虚树上的节点 \(x\),它作为答案当且仅当 \(x\) 到根的路径上存在某个结尾节点 \(endp_i\)\(i\in[l,r]\))。

于是我们扫描线 \(r\),维护 fail 树上 \(x\) 到根的路径的 max,如果这个值大于 \(l\),则 \(x\) 可以贡献答案。

拍扁 dfn 维护,区间取 max(其实修改单调,相当于区间推平),单点查询。采用 \(O(\sqrt L)-O(1)\) 分块。

其实在虚树时并不需要建虚树,只需要知道虚树有哪些点,BIT 维护子树和即可。

\(B=\sqrt L\),时间复杂度 \(O(L\sqrt L)\),时限 \(1s\),卡常,细节较多。

AC Record


P5840 [COCI2015] Divljak

\(n\) 个字符串 \(s_1,s_2,\dots,s_n\),有一个字符串集合 \(T\),初始为空。

有以下两种操作:

  • \(T\) 中加入字符串 \(t\)
  • 查询 \(T\) 中有多少个字符串包含 \(s_x\)

\(1\le n,q\le 10^5\)\(\sum|s|,\sum|t|\le 2\times10^6\)

\(s\) 建 AC 自动机,增加文本串 \(t\)\(s_i\) 的答案增加:

\(t\) 的所有 AC 自动机节点在 \(endp_i\) 的 fail 树子树的出现次数。

建个虚树,搞完了,但其实可以隐式建树,按照 dfn 排序 BIT 维护就行。

具体地,将 \(t\) 对应 AC 自动机节点按照 dfn 排序为 \(p\)\(p_i\to rt\)\(+1\)\(\operatorname{lca}(p_{i-1},p_i)\to rt\)\(-1\)

链加单点查 \(\to\) 单点加子树查,拍扁 dfn 用 BIT 维护。

复杂度 \(O(L|\Sigma|+L\log L)\),我写了 ST 表 lca 所以空间复杂度 \(O(L\log L)\)

AC Record


图论专区

P6914 [ICPC2015 WF] Tours

给定一张 \(n\) 个点 \(m\) 条边的无向图,你需要选择一个颜色种类数 \(k\),然后用这 \(k\) 种颜色给每条边染色,要求对于图中任意一个简单环,每种颜色的边的数量都相同。求所有可行的 \(k\)

保证图无重边,无自环。

\(1\le n,m\le 2\times10^3\)

考虑将简单环划分成若干个不交的环,假如有两个环 \(X,Y\) 有交,那么将它们划分成 \(X-X\cap Y,Y-X\cap Y,X\cap Y\),这样一定可以划分出来。

然后有一个非常牛的结论(我不会证明:

  • 两条边最终属于同一个环当且仅当:对于某一个环,它们要么都在环内,要么都在环外。

trick:划分后无交的简单环删去一条边,剩下的边为割边。

于是枚举一条非割边,计算出删除这条边之后新增的割边数量就能求出他所属简单环长了。

答案是所有简单环长的 gcd 的所有因数。

时间复杂度 \(O(m^2)\)。这题还有神仙哈希做法 \(O(n+m)\)。/jk

AC Record


P10873 [COTS 2022] 帽子 Šeširi

\(n\) 个人,每人有一个黑色或白色的帽子,每个人只能看见别人的帽子。

给每人(看到的 \(2^{n-1}\) 种状态)制定一种策略,使得戴白帽子的至少有一半(向下取整)猜对自己帽子颜色,戴黑帽子的也至少有一半猜对自己帽子颜色。

\(4\le n\le 18\)

对于某一个人看见了 \(S\) 的状态时猜对了:

  • 他是白帽子,整个序列为 \(S_0=S+\{0\}\)
  • 他是黑帽子,整个序列为 \(S_1=S+\{1\}\)

我们建一张二分图,给左部 \(S_0\),右部 \(S_1\) 连边。

给这个二分图定向,对于最终定向的某条边 \(X\to Y\),代表状态为 \(X\) 会猜对一个人,状态为 \(Y\) 会猜错一个人。

那么我们希望每个点的出边至少是它的度数的一半,这是欧拉回路的形式。

但是还有奇点,因为向下取整有 \(1\) 的容错,建虚点连接所有奇点跑欧拉回路即可。

时空复杂度 \(O(n 2^n)\),实现差的话时间复杂度 \(O(n^2 2^n)\)

AC Record


CF1215F Radio Stations

\(n\) 个区间 \([l_i,r_i]\),在 \(1\sim m\) 中选择一个点 \(f\)

假如 \(f\in[l_i,r_i]\) 则可以选择 \(i\)

另有 \(a\) 个限制形如:\(i\)\(j\) 至少要选一个。

另有 \(b\) 个限制形如:\(i\)\(j\) 至多可以选一个。

构造 \(f\) 和选择方案。

\(2\le n,m,a,b\le 4\times 10^5\)

后两个限制明显是 2-SAT 板子。

\(T_i\) 表示选 \(i\)\(F_i\) 表示不选 \(i\)

\(a\) 限制:\(F_i\to T_j\)\(F_j\to T_i\)

\(b\) 限制:\(T_i\to F_j\)\(T_j\to F_i\)

考虑 \(f\) 的限制怎么做,可以大力线段树优化建图(丑陋)。

trick:前缀和优化建图。

\(P_i\) 表示 \([f\le i]\)\(Q_i\) 表示 \([f>i]\)

\(P_i\to P_{i+1}\)\(Q_i\to Q_{i-1}\)

对于 \(f\in [l_i,r_i]\) 可以表示为:

  • \(T_i\to Q_{l_i-1}\)\(T_i\to P_{r_i}\)
  • \(P_{l_i-1}\to F_i\)\(Q_{r_i}\to F_i\)

跑 2-SAT 即可。

AC Record


[ARC153F] Tri-Colored Paths

有一张 \(n\)\(m\) 边的简单无向连通图。

你需要给每条边染上三种颜色之一,使得图中存在一条路径,经过三种不同颜色的边。

求合法染色方案数,对 \(998244353\) 取模。

\(3\le n,m\le 2\times 10^5\)

显然正面考虑特别难,考虑反面情况。

有两种或仅一种颜色的情况是 trival 的,不做赘述。

计算恰好三种颜色并且图不合法的方案数。

下面称这三种颜色为红、黄、蓝。

\(\rule{20cm}{0.05em}\)

先考虑一个弱化问题:图是一棵树。

必存在点 \(x\) 使得连 \(x\) 的边有至少两种颜色。

不妨设 \(x\) 连了红、蓝边。把 \(x\) 当作树的根。

发现 \(x\) 连了红、蓝边的子树内不能有黄边,否则会出现合法路径。

于是黄边只能全部在 \(x\) 连黄边的子树内。

结论:存在点 \(x\) 使得 \(x\) 连出三种颜色的边,且 \(x\) 同一子树内的边和 \(x\) 连向这个子树的边颜色相同。

方案数就很好统计了,枚举一个点作为 \(x\),设度数为 \(d\)

容斥一下,方案数 \(f(d)=3^d-3\cdot 2^d+3\)

总方案数就是 \(\small{\displaystyle\sum_x f(deg_x)}\)

\(\rule{20cm}{0.05em}\)

接下来考虑图的问题。

先考虑环,环长 \(>3\) 则不可能环上有三种颜色。

特殊情况:三色三元环。

  • 三元环仅一个点向外连边,一定是一个点双,方案数为 \(6\)

  • 三元环上有两个点向环外同一个点连边。

    还有特殊情况:

    发现此时每个点都不能再连任何颜色的边。

    \(n=4\) 的这种情况(仅一个点双,\(m\ge 5\))特判即可。

接下来认为环最多两种颜色。

若环上有两种颜色,不妨设为红、蓝。环外必定有一条黄边,由于图连通,这条黄边肯定能走到环上。

环上必有红或蓝边大于 \(2\) 条,则必定有合法路径。

结论:简单环上边的颜色相同。

扩展结论:点双内边的颜色相同。

于是建圆方树,问题变为:将方点染色,使得不存在路径经过三种不同颜色的方点。

用树的结论:必然存在圆点 \(x\) 连出三种颜色的边,且 \(x\) 子树内方点颜色与子树的根相同。

答案即为 \(\small{\displaystyle\sum_x f(deg_x)}\)\(x\) 是圆点。

时间复杂度 \(O(n+m)\)

AC Record


二分图分区

[AGC029F] Construction of a tree

\(n\) 个点,给定 \(n-1\) 个点集 \(S_1,S_2,\dots,S_{n-1}\)\(|S_i|\ge 2\)

从每个 \(S_i\) 中选出两个不同的数 \(a_i,b_i\),连接 \(a,b\) 两个点。

构造方案使最后连成一颗树。

\(1\le n\le10^5\)\(1\le\sum|S_i|\le 2\times10^5\),时限 \(4s\)

令每个集合选出的 \(a_i,b_i\) 最后在树上 \(a_i\)\(b_i\) 的父亲。

假设树根为 \(rt\),那么 \(b_i\) 互不相同,且 \(\{b_i\}=\{x|x\ne rt\}\),意思是,除了 \(rt\) 每个点都有一条到其父亲的边。

那么我们得出一个必要条件:从每个集合中选出 \(1\) 个数,可以选出 \(n-1\) 个互不相同的数。

我一看,这不是二分图吗,左侧点表示选出的数,右侧点表示点集编号,最大匹配要等于 \(n-1\)

找到最大匹配(不等于 \(n-1\) 就无解)可以确定 \(rt\)\(b\),我们考虑这样一个 bfs 构造方法:

当前点为 \(x\)(初始为 \(rt\)),找到 \(x\) 所属的点集 \(y\),若 \(b_y\ne x\) 且未确定 \(a_y\),则 \(a_y=x\) 并将 \(b_y\) 加入 bfs 队列。

假设没有这样 bfs 没能构造完,构造出的 \(a_i\) 的集合为 \(T\),注意到 \(x\) 属于的点集 \(y\) 相当于二分图上 \(x\to y\),那么二分图左侧为 \(T\) 不符合 Hall 定理,矛盾,所以肯定可以构造出来。

还有一种构造不出的情况为可以把 \(n-1\) 个点集划分为两份,两份的点集两两不交,bfs 判断是否构造完即可。

用 dinic 跑二分图最大匹配,时间复杂度 \(O(N\sqrt N)\)\(N=\sum|S_i|\))。

AC Record


[AGC067A] Big Clique Everywhere

给你一个 \(n\) 个点 \(m\) 条边的简单无向图 \(G\),你需要判定 \(G\) 中是否所有点导出子图都存在点数不少于一半的团。

多组数据,\(1\le T\le 10^3\)\(1\le\sum n\le 10^5\)\(0\le\sum m\le 10^6\)

trick:原图中的一个团是补图中的独立集。

trick:只有二分图不存在导出子图最大独立集 \(<\dfrac{|V|}{2}\)

证明:奇环最大独立集 \(<\dfrac{|V|}{2}\)

于是变为判定 \(\neg G\) 为二分图。

注意到 \(\neg G\) 边数为 \(\dfrac{n(n-1)}{2}-m\),二分图至多 \(\lfloor\dfrac{n^2}{4}\rfloor\) 条边,故 \(\dfrac{n(n-1)}{2}-m>\lfloor\dfrac{n^2}{4}\rfloor\) 不合法。

判掉以后 \(m\)\(O(n^2)\) 级别的,直接 \(O(n^2)\) 求出补图判断二分图即可。

时间复杂度 \(O(m)\)

AC Record


P9726 [EC Final 2022] Magic

序列 \(a_{0\dots 2n}\) 初始全为 \(0\),有 \(n\) 次覆盖操作 \(l_i,r_i\) 表示把 \([l_i,r_i)\) 区间覆盖为 \(i\)

可以任意排列操作顺序,最大化 \(\sum\limits_{i=0}^{2n-1}[a_i\ne a_{i+1}]\),求这个最大值。

保证 \(l_i,r_i\) 互不相同。

\(n\le 5\times10^3\)。时限 \(3s\)空限 \(16M\)

若位置 \(x\) 最终满足 \(a_{x}\ne a_{x+1}\)

找到操作 \(p\) 满足 \(l_p=x+1\)\(r_p=x+1\)。只有 \(p\) 操作后才能 \(a_{x}\ne a_{x+1}\)

还要满足之后不会有操作把 \(x,x+1\) 都覆盖了,也就是 \(p\) 之后不存在操作 \(q\) 满足 \(l_q\le i<r_q-1\)

于是可以考虑操作 \(p,q\) 的顺序对答案的影响:

不妨设 \(l_p<l_q\)

  • $[l_p,r_p)\cap[l_q,r_q)=\emptyset $,无交,不影响。

  • \([l_p,r_p)\subseteq [l_q,r_q)\),包含,一定是先操作 \(p\)

  • \(l_q<r_p\),有交但不包含,先操作 \(p\)\(a_{l_q}=a_{l_q+1}\),先操作 \(q\)\(a_{r_p}=a_{r_p+1}\)

第三种情况可以描述为:\(l_q\)\(r_p\) 只能选一个。

按照 \(l_q\longleftrightarrow r_p\) 的方式建图后答案为最大独立集。

\(l_i,r_i\) 互不相同,这个图为二分图。

trick:\(\small\mathbf{二分图最大独立集大小}=\small\mathbf{点数}-\small\mathbf{二分图最大匹配}\)

空限太小,bitset 邻接矩阵跑 dinic,时间复杂度 \(O(\frac{n^3}{\omega})\),但是 dinic 常数你不用担心。

AC Record


树上问题专区

P8990 [北大集训 2021] 小明的树

给一棵 \(n\) 个点的树(根为 \(1\))和一个长为 \(n-1\) 的操作序列 \(a\)\(a\)\(2\sim n\) 的排列。

定义这棵树的权值为:

初始所有点为黑色,依次把 \(a_1\dots a_{n-1}\) 染为白色,每次染色后若树是“美丽”的,则树的权值加上当前白点连通块数量。

树是“美丽”的当且仅当每个白点的子树内都是白点。

\(m\) 次修改:断掉 \((x1,y1)\) 的边并将 \((x2,y2)\) 连边,保证修改后还是一棵树。

求出初始和 \(m\) 次修改后的树的权值。

\(1\le n,m\le 5\times10^5\),时限 \(3s\)

观察性质:

树是“美丽”的当且仅当每个白点的子树内都是白点,这个太难维护了,我们从黑点的角度考虑。

我们将其转化为:每个白点的子树内都没有黑点,也就是每个黑点到根的路径上都没有白点。

注意到根是黑点,所以这个条件相当于:黑点形成一个连通块。

trick:每个白点的子树内都是白点 相当于 黑点形成一个连通块。

然后点边容斥:

trick:黑点连通块数量 = 黑点数量 - 两端都是黑点的边的数量。

时刻 \(i\) 的黑点数量为 \(n-i\),定义 \(t_x\)\(x\) 被操作的时刻(\(t_{a_x}=x\)),对于每条边 \((u,v)\),时刻 \([1,\min(t_u,t_v))\) 内它两端都是黑点,黑点连通块个数 \(-1\)

这样就能用线段树维护 \(f_i\) 表示时刻 \(i\) 的黑点连通块个数。

\(f_i=n-i\),对于每条边 \((u,v)\)\(\forall i\in[1,\min(t_u,t_v)),f_i\gets f_i-1\)

然后还有一个问题:白点连通块数量怎么求?

注意到每个白点连通块必为原树一整棵子树,则 白点连通块数量 = 两端是黑点、白点的边的数量

同样的,对于每条边 \((u,v)\),时刻 \([\min(t_u,t_v),\max(t_u,t_v))\) 内它两端是黑点、白点,白点连通块个数 \(+1\)

这样就也能用线段树维护 \(g_i\) 表示时刻 \(i\) 的白点连通块个数。

即对于每条边 \((u,v)\)\(\forall i\in[\min(t_u,t_v),\max(t_u,t_v)),g_i\gets g_i+1\)

现在我们考虑如何查询,答案即为 \(\sum\limits_{f_i=1}g_i\)

注意到 \(f_i\ge 1\),兔队线段树维护 \(f\) 的区间最小值,区间最小值个数,区间 \(f\) 最小的位置的 \(g\) 的和。

修改对边 \((x1,y1)\)\((x2,y2)\) 贡献重新算即可。

时间复杂度 \(O((n+q)\log n)\),读入量略大。

AC Record


[ARC181E] Min and Max at the edge

给一个 \(n\)\(m\) 边的图 \(G\),定义生成树是“好的”满足:

对于非树边 \((u,v)\)\(u<v\)),\(u=\min\limits_{x\in path(u,v)}x\)\(v=\max\limits_{x\in path(u,v)}x\)

也就是生成树上 \(u,v\) 的简单路径的编号最小、最大点分别是 \(u,v\)

对于每条边,求:删去这条边后的图 \(G'\) 是否存在“好的”生成树。询问相互独立。

\(1\le n\le 2\times10^5\)\(n-1\le m \le 2\times10^5\)

考虑非树边 \((u,v)\) 的限制,看着很像 kruscal 的证明:非树边权值大于等于所有路径上的树边的权值。

但是这题是点权,考虑转化为边权。

需要构造一种算边权方式使得 \(w(u,v)\) 大于所有树边 \((x,y)\) 权值。

题目条件有 \(u\le x\le y\le v\)\(w\) 需要满足 \(\forall u\le x\le y\le v,w(x,y)<w(u,v)\)

\(w(u,v)\) 为二元组权值 \((-u,v)\),权值双关键字比较,这样满足条件。

可以将双关键字压缩,变为 \(w(u,v)=(n-u)\times(n+1)+v\)

于是“好的”生成树必须是按 \(w\) 生成边权的最小生成树。

这个最小生成树的非树边 \((u,v)\) 必定满足 \(u=\min\limits_{x\in path(u,v)}x\),但是不一定满足 \(v\) 的限制。

倒着做一遍,\(w(u,v)\) 为二元组权值 \((v,-u)\),双关键字压缩 \(w(u,v)=v\times(n+1)-u\),这样的最小生成树满足 \(v\) 的限制。

我们注意到 \(w\) 互不相同,所以最小生成树唯一,判断这两棵生成树是否相同即可。

判断树是否完全相同可以集合哈希,现在问题来了:删除某一条边后的最小生成树如何做?

先求出原来的最小生成树。假设删去了边 \((u,v)\),在原来的最小生成树上 \(u\)\(v\) 的父亲,那我们相当于断开了 \(v\) 整棵子树,变成两个连通块。

考虑 kruscal 的过程,我们需要在剩下的边中选择一条最大的边 \((x,y)\) 连接两个连通块。

那么我们需要求出除去 \((u,v)\) 最小的边满足 \(x\)\(v\) 子树外,\(y\)\(v\) 子树外。

拍扁 dfn 序,令 \([l,r]\) 表示 \(v\) 的子树 dfn 区间,\(x,y\) 代指 \(dfn_x,dfn_y\)

那么 \(x\notin[l,r],y\in[l,r],(x,y)\ne(dfn_u,l)\)

拆为两部分:

  • \(x\in[1,l-1],y\in[l,r]\)
  • \(x\in[r+1,n],y\in[l,r]\)

只计算不在原来的最小生成树上的 \((x,y)\),则不会算到 \((u,v)\)

分别矩形求最大值即可,发现 \(x\) 必为前后缀,扫描线+线段树维护即可。

时间复杂度 \(O(m\log m+m\log n)\),空间复杂度 \(O(n)\)

样例的最小生成树:

AC Record


DP 专区

P9040 [PA2021] Desant 2

有序列 \(a_{1\dots n}\),给定长度 \(k\)\(q\) 此询问:

询问区间 \([l,r]\),从 \(a_{l\dots r}\) 中选出若干个不相交的长度为 \(k\) 的区间,求选出的数的和的最大值。

\(1\le n,q\le 10^5\)\(1\le k\le n\)\(|a_i|\le 10^9\)

不知道为什么时限 \(10s\),空限 \(1G\),PA 也太大方了吧,正解完全可以 \(1s\) 的。

PA 原题 时限 \(42s\),这不是直接 \(O(qn)\) 冲过?

回归正题,有显然 \(O(qn)\) DP:

\(s_i=\sum\limits_{j=1}^i a_j\),询问区间 \([l,r]\),设 \(dp_i\)\(l\sim i\) 的答案。

\[dp_i=\max(dp_{i-1},dp_{i-k}+s_i-s_{i-k}) \]

将序列每 \(k\) 个分块,画出 DP 转移的 DAG:(一个 \(n=12,k=3\) 的例子,蓝色框住的为一块。)

问题形如 \(l\to r\) 的最长路形式。

记块数 \(m=\lceil\dfrac{n}{k}\rceil\),我们对这 \(m\) 个块分治。

分治区间 \([L,R]\),中点 \(M\),计算左端点在 \([L,M]\) 块内,右端点在 \([M+1,R]\) 块内的询问。

注意到最长路一定每个块经过一遍,故一定经过第 \(M\) 块的某个点,称这个点为“断点”。

处理出分治区间每个点到第 \(M\) 块的所有点的最长路,询问 \(O(k)\) 枚举“断点”。

时间复杂度 \(O(n\log n+qk)\),那这整了半天不还是一样吗。

观察到这个分治其实是对 \(m\times k\) 的矩形的列的分治。

trick:对面积为 \(S\) 的矩形分治,选择行与列中较大维分治,较小维长度 \(O(\sqrt{S})\)

那我们能对列分治,为什么不能对行分治呢。

但由于这些红色边的存在,所以不满足必须每个块经过一次的性质。

只有第一次对行分治是会考虑红色边,需要特殊处理。

把上述性质该为:一定经过第 \(M\) 块的某个点或者某条红色边。

我们将红色边也视为一个“断点”,处理出分治区间每个点到红色边端点的最长路。

由于红色边数量和列数同阶,所以复杂度不变。

设当前分治矩形面积为 \(S\),时间复杂度 \(T(S)=2T(\dfrac{S}{2})+O(S\sqrt S)=O(S\sqrt S)\)

总共时间复杂度 \(O((n+q)\sqrt n)\)


贪心专区

CF335F Buy One, Get One Free

\(n\) 个馅饼,第 \(i\) 个价格为 \(a_i\)

购买一个价格 \(v\) 的馅饼可以免费兑换一个价格 \(<v\) 的馅饼。

求买完这 \(n\) 个馅饼的最小代价。

\(1\le n\le 5\times10^5\)\(1\le a_i\le 10^9\)

这种东西,除了 DP 就是反悔贪心。

DP 看起来(?)没前途,考虑反悔贪心。

先合并价值相同的馅饼,按照价值从大到小排序。

现在的馅饼价格为 \(x\),有 \(c\) 个。

之前一共获得了 \(s\) 个馅饼,其中有 \(t\) 个是兑换的。

当前有 \(s-2t\) 个购买的馅饼还没有兑换。

先贪心地全部兑换,兑换 \(\min(s-2t,c)\) 个。

剩下的 \(r=c-\min(s-2t,c)\) 个需要购买或反悔。

用一个小根堆 \(P\) 维护兑换的馅饼。

注意 \(P\) 维护的是兑换的馅饼,也就是说兑换的价值和为 \(P\) 价值和,兑换的个数就是 \(|P|\)

假设之前兑换了一个价格为 \(y\) 的馅饼(\(P\) 的堆顶):

  • \(x>y\)

    • \(r>1\)

      兑换 \(y\) 改为买 \(y\),多出来 \(2\) 个兑换名额,用于兑换 \(2\)\(x\),肯定更优。

      \(P\) 的操作:加入 \(2\)\(x\)

    • \(r=1\)

      兑换 \(y\) 改为买 \(y\),多出来 \(2\) 个兑换名额,用于兑换 \(1\)\(x\),还剩 \(1\) 个名额以后用。

      \(P\) 的操作:加入 \(x\)

  • \(x\le y\)

    • \(r>1\)

      • 保留 \(y\),买 \(x\),相当于不改变兑换决策。
      • 购买 \(y\),多出来 \(2\) 个兑换名额,兑换 \(2\)\(x\)
      • 购买 \(y\),用其他名额兑换 \(x\)

      我们抽象出一个价格为 \(2x-y\) 的馅饼,和原本价格为 \(y\) 的馅饼加入堆。

      如果 \(2x-y<0\) 说明买 \(2\)\(x\) 一定更优,不能加入 \(2x-y\) 的馅饼。

      由堆内是否剩下 \(y\)\(2x-y\) 能描述反悔的决策:

      • 只剩 \(y\),意味着 \(2\)\(x\) 没被兑换,即买了 \(2\)\(x\)
      • 只剩 \(2x-y\),意味着买了 \(y\) 兑换 \(2\)\(x\)(相当于免费买 \(y\) 兑换 \(2x-y\)),多出来的 \(2\) 个名额对应 \(y\)\(2x-y\)
      • 都剩下,意味着买了 \(y\),用别的名额兑换 \(2\)\(x\),名额数目依然对得上。

      这一步非常抽象,对一对脑电波才行。

      \(P\) 的操作:加入 \(y\)\(2x-y\)

    • \(r=1\)

      只有保留兑换 \(y\) 的可能,这样肯定比兑换 \(x\) 或者买 \(y\) 更优。

      \(P\) 的操作:加入 \(y\)

注意:每个 \(x\) 操作完所有 \(y\) 才能执行加入操作,否则可能出现买 \(x\) 兑换 \(x\) 的情况。

至于为什么是小根堆,因为反悔之前兑换的更少的肯定更优。

时间复杂度 \(O(n\log n)\)

AC Record


数论专区

SP34112 UDIVSUM - The Sum of Unitary Divisors

\[\sigma^*(x)=\sum_{d|x}[\gcd(d,\frac{x}{d})=1]d \]

求:

\[\sum_{i=1}^n \sigma^*(i) \]

答案对 \(2^{64}\) 取模。

\(n\le 5\times 10^{13}\),数据组数 \(T\) 详见原题。

时限 \(10s\)

\[\begin{aligned} &\sum_{i=1}^n\sum_{d|i}[\gcd(d,\frac{i}{d})=1]d\\ =&\sum_{i=1}^n\sum_{d|i}d\sum_{r|d,r|\frac{i}{d}}\mu(r)\\ =&\sum_{d=1}^nd\sum_{r|d}\mu(r)\sum_{d|i}[r|\frac{i}{d}]\\ =&\sum_{d=1}^nd\sum_{r|d}\mu(r)\lfloor\frac{n}{dr}\rfloor\\ =&\sum_{r=1}^{\lfloor\sqrt n\rfloor}\mu(r)\sum_{r|d\operatorname{and}dr\le n}d\lfloor\frac{n}{dr}\rfloor\\ =&\sum_{r=1}^{\lfloor\sqrt n\rfloor}r\cdot \mu(r)\sum_{d=1}^{\lfloor\frac{n}{r^2}\rfloor}d\lfloor\frac{n}{d r^2}\rfloor\\ =&\sum_{r=1}^{\lfloor\sqrt n\rfloor}r\cdot \mu(r)\sum_{d=1}^{\lfloor\frac{n}{r^2}\rfloor}d\lfloor\frac{\lfloor\frac{n}{r^2}\rfloor}{d}\rfloor \end{aligned} \]

定义

\[f(x)=\sum_{i=1}^x i\lfloor\frac{x}{d}\rfloor \]

则有:

\[\begin{aligned} &\sum_{r=1}^{\lfloor\sqrt n\rfloor}r\cdot \mu(r)\sum_{d=1}^{\lfloor\frac{n}{r^2}\rfloor}d\lfloor\frac{\lfloor\frac{n}{r^2}\rfloor}{d}\rfloor\\ =&\sum_{r=1}^{\lfloor\sqrt n\rfloor}r\cdot \mu(r)\cdot f(\lfloor\frac{n}{r^2}\rfloor) \end{aligned} \]

整除分块计算 \(f(x)\)。时间复杂度:

\[\begin{aligned} &\sum_{r=1}^{\lfloor\sqrt n\rfloor}\lfloor\sqrt{\frac{n}{r^2}}\rfloor\\ =&\sum_{r=1}^{\lfloor\sqrt n\rfloor}\lfloor\frac{\sqrt n}{r}\rfloor\\ =&O(\sqrt n\ln n) \end{aligned} \]

然后恭喜你被卡常了。

整除分块有一个 卡常trick

观察里面那张图:

\[\begin{aligned} f(x)&=\sum\limits_{i=1}^x i\lfloor\dfrac{x}{i}\rfloor\\ &=\sum\limits_{i=1}^{\lfloor\sqrt{x}\rfloor}(i\lfloor\dfrac{x}{i}\rfloor+\dfrac{\lfloor\dfrac{x}{i}\rfloor\cdot (\lfloor\dfrac{x}{i}\rfloor+1)}{2})-\dfrac{\lfloor\sqrt{x}\rfloor\cdot (\lfloor\sqrt{x}\rfloor+1)}{2}\cdot\lfloor\sqrt{x}\rfloor \end{aligned} \]

然后还是 TLE,经过实验发现被 Input 1:\(1\le n\)\(T\le 5\times10^4\) 卡掉了。

\(O(n\sqrt n)\) 打出 \(1\sim 5\times 10^4\)\(f\) 即可。

AC Record


交互

P7824 「RdOI R3」毒水

\(n\) 瓶水,其中有一瓶有毒。

\(k\) 只小白鼠,其中恰好有一只是变异鼠。

每只小白鼠能被用做一次实验,让它喝若干瓶水:

  • 非变异鼠喝到毒水会死。
  • 变异鼠喝不到毒水会死。

找到哪瓶是毒水。

注意:所有实验做完才会返回实验结果。

subtask 分值 \(n\) \(k\ge\)
\(1\) \(1\) \(=1\) \(0\)
\(2\) \(9\) \(\le 1000\) \(3000\)
\(3\) \(20\) \(\le 1000\) \(30\)
\(4\) \(30\) \(8\le n \le 16\) \(7\)
\(5\) \(40\) \(\le 1000\) \(15\)

subtask 2 提示我们:\(3\) 只小白鼠能够确定一瓶水是否有毒。

trick:二进制分组。

假如无变异鼠,第 \(i\) 只小白鼠喝二进制第 \(i\) 位是 \(1\) 的编号的水,就能 \(\log n+1=10\) 次确定。

现在有变异鼠,可以继续使用 \(3\) 只确定一个二进制位,就是 subtask 3。

\(3\) 只一位太浪费了,还是使用 \(1\) 只一位,称这 \(\log n+1=10\) 只为 \(A\) 类鼠。

二进制分组套二进制分组,用 \(\log(|A|)+1=4\) 只去二进制分组喝 \(A\) 类鼠喝过的水,称为 \(B\) 类鼠。

但我们并不知道变异鼠 \(A\) 类、\(B\) 类还是剩下的 \(1\) 只。

用剩下的一只去喝 \(B\) 类鼠喝过的奇数次的水,称为 \(C\) 鼠。

  • \(B+C\) 有奇数只被毒死。

    \(B+C\) 每瓶水都喝了偶数次,应毒死偶数只非变异鼠,这说明这之中有一只变异鼠。

    \(A\) 类鼠都是非变异鼠,用它们判断。

  • \(5\) 只有偶数只被毒死。

    同理,说明 \(A\) 类有变异鼠。

    \(B\) 类鼠检验出它和它所管辖的 \(A\) 类鼠状态是否死了奇数只,以检测出变异鼠。

编号用 \(0\sim n-1\),能省下一点二进制分组。

AC Record


杂项

CF1545D AquaMoon and Wrong Coordinate

\(n\) 个人站在一根数轴的正半轴的整点上,向数轴正方向做匀速直线运动。

给出他们 \(0\sim k-1\) 时刻的坐标集合(顺序有可能被打乱)。

\(nk\) 个数当中有一个数被修改成了任意值,求这个数位于哪个时刻的坐标集合和它原来的值。

保证第 \(0\) 时刻不会被修改。

\(5\le n\le 10^3\)\(7\le k\le 10^3\)

以下认为时刻 1-index,即时刻是 \(1\sim k\)

\(i\) 时刻坐标和减去 \(i-1\) 时刻坐标和能得到位移和,位移和不对的那个时刻就是被修改的时刻。

通过位移和能够知道修改后这个数变大了多少。

逆天观察:考虑一下平方和有什么规律。(天知道是谁想出来的)

\(f(t)=\sum\limits_{i=1}^n {x_{t,i}}^2\)

  • \[f(t)-f(t-1)=\sum_{i=1}^n {x_{t,i}}^2-(x_{t,i}-v_i)^2=2\sum_{i=1}^n x_{t,i}\cdot v_i-\sum_{i=1}^n {v_i}^2 \]

  • \[f(t+1)-f(t)=\sum_{i=1}^n (x_{t,i}+v_i)^2-{x_{t,i}}^2=2\sum_{i=1}^n x_{t,i}\cdot v_i+\sum_{i=1}^n {v_i}^2 \]

进行一波减法:

\[f(t+1)+f(t-1)-2f(t)=2\sum_{i=1}^n {v_i}^2 \]

这是一个定值。

然后拿出刚才找到的被修改的时刻 \(s\) 和修改的增加量 \(\Delta\)

枚举 \(i\)\(x_{s,i}\gets x_{s,i}-\Delta\),检查 \(f(s-1)+f(s+1)-2f(s)\) 是否合法,就能找出修改的 \(x_{s,i}\)

注意一些细节:

  • 不存在 \(f(k+1)\),故 \(s=k\) 时检查 \(f(k)+f(k-2)-f(k-1)\) 是否合法。

  • 选取连续三个正确的 \(f\) 以确定那个定值 \(2\sum\limits_{i=1}^n {v_i}^2\)\(s>3\) 选取 \(1,2,3\),否则选取 \(4,5,6\)

AC Record


CF1770F Koxia and Sequence

posted @ 2025-02-09 07:17  Mathew_Miao  阅读(6)  评论(0)    收藏  举报