NKSWC 集训总结
数据结构
单调队列优化 dp
一般形式:
\[f_i=\max\limits_{k=i-len}^{i-1}\{f_k+w_k\}+w' \]即 dp 方程由 可以在转移前维护的一段连续最值 + 在当前状态下已经确定,或可以预处理并以较低复杂度计算的元素(视作常量)组成。
此时可以将其视作滑动窗口处理,用单调队列维护 \(k\),使得 \(f_k\) 为最值。每次转移可以以均摊 \(O(1)\) 的复杂度计算其内部最值。
不会单调队列的出门左转 OI-wiki。
单调队列优化多重背包
下文中变量含义与题面一致。
回顾一下多重背包的朴素转移式:
令 \(lim=\min\{\lfloor\frac{j}{w_i}\rfloor,m_i\}\),则 \(i\) 一定时,有
令 \(d=j\bmod w, b=\lfloor\frac{j}{w}\rfloor\),得
设 \(b-c=k\),则有
这时方程化为了单调队列优化的一般形式。
即可以将 \(k\) 对于 \(f_{kw+d}-vk\) 的最值的最优值放进队列里滑动取值。
注:
- 由于 \(c\in[0,lim]\),有 \(k=(b-c)\in[b-lim,b]\)。故队列长度最长为 \(lim+1\)。需要动态维护其长度。
【SCOI 2010 DAY1】股票交易
设 \(f_{i,j}\) 为在第 \(i\) 天手上仍持有 \(j\) 张股票所能取得的最大收益。
对于每个阶段,共有 4 种决策:
-
初始化:凭空买入。转移方程为 \(f_{i,j}=-AP_i\cdot j\quad(j\le AS_i)\)。
-
睡觉,跳过这一天。转移方程为 \(f_{i,j}=f_{i-1,j}\quad (i\ge 1)\)。 -
买买买。买入前持有 \(k\) 张股票。每天可以买入 \(AS_i\) 张,且两次交易之间至少要间隔 \(w\) 天,所以两次交易的日期为 \(i\) 与 \(i-w-1\)。此时需保证 \(i\geq w+2\)。 故显然有转移方程 \(f_{i,j}=\max\limits_{k\in[j-AS_i,j]}\{f_{i-w-1,k}-(j-k)AP_i\}\quad(i\geq w+2)\)。
-
卖卖卖。卖出前持有 \(k\) 张股票。和买入的方程类似,为 \(f_{i,j}=\max\limits_{}\{f_{i-w-1,k}+(k-j)BP_i\}\quad(i\geq w+2)\)。
综上,转移方程为
然后这一坨的时间复杂度是 \(O(n^3)\)。此题要求的时间复杂度为 \(O(n^2)\)。考虑优化后两个方程。
将 \(j\) 从 \(\max\) 中提出后,得
转移为单调队列优化的一般式。此时 \(\max\) 内部元素可以均摊 \(O(1)\) 处理。
可以在单调队列中加入目前的最优 \(k\) 进行转移,并维护队列长度。
由于卖出会导致持有股票越来越少,即 \(k\) 单调不降,需换一个单调方向。
并查集
好像除了维护集合并没有什么卵用。
线段树
待填。
图论
拓扑排序
差分约束
多用于解决有多种不等关系限制的问题。形式化地,有
其中 \(y\) 为已知量。
对于单一不等式 \(x_a-x_b=y_c\),移项得 \(x_a=x_b+y_c\),满足最短路三角形不等式 \(d_v=d_u+w_{u,v}\),可以转换为图论问题。
对于每一组 \((c_i,c'_i)\) 连边 \(E(c'_i,c_i)\),权值为 \(y_{c_i}\)。此时对于此图的最短路,\(x\) 可以保证最大解;反之对于最长路 \(x\) 即为最小解。
可以对于每个点 \(u\) 连一条 \((0,u)\) 的边后以 \(0\) 为源点跑最短 / 长路。
【POI2015】PUS
有一个长度为 \(n\) 的序列 \(A\),其中有 \(s\) 个数已知。对于数列中的 \(m\) 个区间 \([L_i,R_i]\),有集合 \(K_i\) 满足 \(\forall x \in K_i,y \in (\overline{K_i} \cap [L_i, R_i])\) 有 \(x \in [L_i, R_i] \wedge A_x > A_y\)。任意构造一组满足条件的方案。
数据范围:
- \(1 \le s \le n \le 10^5\)
- \(1 \le m \le 2 \times 10^5\)
- \(1\le L \le R \le n, 1 \le k \le r - l, \sum |K| \le 3 \times 10 ^ 5\)
差分约束+线段树优化建图。
该问题共有两种约束:
- \(A_p=x\),可直接对 \(d_p\) 赋值为 \(x\)。
- \(\forall q \in (\overline{K_i} \cap [L, R])\) 有 $ A_p > A_q$,即 \(A_p - A_q \ge 1\)。
此时 \(p\) 将 \([L,R]\) 分为 \(|K_i| + 1\) 段小区间。对于 \(p\) 及每一段小区间分别连边即可。
但是直接连边总边数为 \(n^3\) 级别,原地爆炸。
即使建立虚点总边数也在 \(n^2\) 的级别。
考虑使用线段树优化建图,总边数降为 \(|K| + \sum |K| \log n + 2n < 6 * 10^6\),可以接受。
强连通 / 双连通
强连通
Tarjan 算法
其核心为点在 dfs 搜索树上的时间戳。令 \(S_u\) 为 \(u\) 在 dfs 搜索树上子树的点集。
在 dfs 的过程中维护 \(low_u\),表示 \(u\) 及 \(v \in S_u\) 通过原图上的边能够到达的最小时间戳。
显然,对于搜索树上的每个节点 \(u\),若 $\forall v \in S_u $ 有 $ dfn_v \neq low_v$ 时,\(\{u, S_u\}\) 一定属于同一个强连通分量。
对于每次的向下拓展,共有三种情况:
- \(dfn_v=0\),即 \(v\) 还没有被访问,向下搜索。此时根据 \(low\) 的定义,更新为 \(low_u:=\min(low_u,low_v)\)。
- \(scc_v=0\),即 \(v\) 已被访问,但仍确认强连通分量,即 \(e(u,v)\) 为搜索树上的横叉边或返祖边。此时根据定义,更新为 \(low_u:=\min(low_u,dfn_v)\)。
- \(scc_v \neq 0\),即 \(v\) 已确认强连通分量。不管了。
【SNOI2017】炸弹
容易发现这是一道图论问题。
首先,显然应将炸弹坐标离散化,转移为编号。
由于题目保证 \(x\) 单调上升,可以二分查找对于每个炸弹单次爆炸能够炸到的最左及最右炸弹编号,记作 \(L_i, R_i\)。
对于每个炸弹 \(i\),向 \([L_i,R_i]\) 的每个炸弹连边。
为避免出现有环的情况,先跑一遍强连通分量缩点。
在反图上拓扑排序,更新点 \(u\) 能够覆盖的最远左、右编号,记作 \(l_i,r_i\)。
具体地,令炸弹单次爆炸能够覆盖的集合为 \(S_u\),则有 \(l_u=\min\limits_{v \in S_u}(l_v)\),\(r_u\max\limits_{v \in S_u}(r_v)\)。
但是时空复杂度均为 \(O(n^2)\),不能接受。
由于此题需要区间连边,考虑线段树优化建图。可以将边数降为 \(O(n\log n)\) 的级别。
Tarjan 算法线性,总时间复杂度为 \(O(n \log n)\),可以接受。
割点与桥
- 桥:在搜索树上且未被非树边覆盖的树边即为桥。覆盖指对于图上一路径 \(u \to v\) 存在边 \(e(u,v)\),则称 \(u \to v\) 被 \(e(u,v)\) 覆盖。对于 \(e(u,v)\),若满足 \(low_v>dfn_u\),即在搜索树上不存在 \(v\) 到其祖先的路径。
- 割点:显然地,若点 \(u\) 在搜索树上不存在到其祖先(不包括父亲)的路径,\(u\) 即为割点。
欧拉路
【IMO2020 D1T3】宝石装箱
有 \(4n\) 颗宝石,价值分别为 \(1,2,\cdots,4n\)。
宝石的颜色共有 \(n\) 种,每种颜色恰好有 \(4\) 颗宝石。
将宝石分为两堆,满足
- 两堆宝石总价值相等;
- 每一堆均恰有每种颜色的 \(2\) 颗宝石。
若有解,输出方案;否则输出
-1
。
可以考虑将颜色看作点,分在同一组的宝石互相连边。若没有第二个条件的限制,显然可以将价值为 \(i\) 的颜色与价值为 \(4n-i\) 的颜色连边,可以保证每条边端点点权和为 \(4n\)。此时每个点的度数定然为 \(4\),存在欧拉回路。跑出欧拉回路后对于相邻的点间隔选边,显然可以满足第二个限制。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】