NOIP算法学习笔记
第一板块——基本算法
搜索
双向广搜
常见用法
补充
- 双向广搜判无解的效率一般比不上普通广搜
题目
- P1379 八数码难题
简要思路:把 \(string\) 的状态存到 \(map\) 中,再把每个位置的可拓展的状态代表出来,跑双向 \(bfs\) 即可
第二板块——数学
位运算
常见用法
组合数学
排列组合
常见用法
补充
-
\[\begin{pmatrix}n \\m \\ \end{pmatrix} = \begin{pmatrix}n-1 \\m \\ \end{pmatrix} + \begin{pmatrix}n-1 \\m-1 \\ \end{pmatrix} \]
-
\[\sum^n_{i=1} \normalsize\begin{pmatrix}n \\i \\ \end{pmatrix} = 2^n \]
题目
- P7481 梦现时刻
题解
简要思路:推 \(F_{a,b}\) 递推式,用组合数递推式化简
第三板块——图论
拓扑排序
常见用法
题目
P1347 排序
简要思路:按照小于关系拓扑建边,有以下几种情况:
- 出现环,则不合法
- 图不连通但没出现环,则有无穷多解
- 否则,有唯一解
差分约束
常见用法
补充
-
差分约束中,跑最短路还是最长路看不等式的符号,一般而言,\(dis_u \le dis_v+w\) 跑最短路,\(dis_u \ge dis_v+w\) 跑最长路
-
差分约束中,一般情况下(建超级源点 \(0\),初始 \(dis_0 = 0\)),
如果跑最短路,那么对于 \(i\in[1,n],dis_i \le 0\)。
如果跑最长路,那么对于 \(i\in[1,n],dis_i \ge 0\)。
所以,当题目中要求 \(i\in[1,n],A_i \le 0\),可以直接跑最短路,反之跑最长路 -
形如 \(A_u =(\le或\ge) x\) 的等式,可以建超级点 \(n+1\),转化为 \(dis_u =(\le或\ge) dis_{n+1}+x\),这里只讨论跑最短路的情况,最长路同理:
跑最短路后,可以发现,超级点的值也会更新,此时,超级点的值其实为 \(\min_{i\in[1,n] \land A_i确定} A_i\),但我们想要的是 \(dis_0 = 0\),所以 \(dis_i\) 的真实值为 \(dis_i-dis_0\)
题目
-
P4926 [1007] 倍杀测量者
简要思路:给式子两边都取 \(log\),套差分约束板子即可 -
P5590 赛车游戏
简要思路:转换为 \(dis_a - dis_b \in [1,9]\),跑差分约束。有几点要注意:
1.注意判断 \(1\) 能否到 \(n\)
2.如果有边不在 \(1\) 到 \(n\) 的路径上,就把这些边去掉,不然会影响差分约束的判断
最短路
易错点
- 假如有负权边,当 \(w\) 为负数时,如果 \(dis_u\) 和 \(dis_v\) 为 \(inf\) 时,\(dis_v\) 就会被更新,所以要么最后判断时不写 "\(==inf\)",要么在松弛时判断 \(dis_u\) 不为 \(inf\)(\(Floyd\) 松弛同理)
Bellman-Ford
常见用法
补充
- 有边数限制的题可以考虑 \(Bellman-Ford\)
比如:求从 \(1\) 号点到 \(n\) 号点的最多经过 \(k\) 条边的最短距离
细节:\(Bellman-Ford\) 有每轮更新有串联效应,比如在一轮中,\(1\) 更新 \(2\) ,更新了的 \(2\) 又更新 \(3\) ,这样就不保证最多经过 \(k\) 条边,所以应再加一维,可用滚动数组优化。
Dijkstra
常见用法
题目
-
P1144 最短路计数
简要思路:松弛时,\(dis_u+w<dis_v\) 就 \(cnt[v]=cnt[u]\),\(dis_u+w=dis_v\) 就 \(cnt[v]+=cnt[u]\),原因显然 -
P1462 通往奥格瑞玛的道路
简要思路:直接做不容易,考虑二分答案,于是 \(check(x)\) 就要判断能否从 \(1\) 到 \(n\) 经过一些边,边权 \(\le x\),且边权和小于血量。重新建图,跑最短路判断即可 -
P5304 [GXOI/GZOI2019] 旅行者
简要思路:考虑把点分成两个集合,建两个超级源点分别与这两个集合的点连边,则它们的最短路就是两集合之间最短路的最小值。但任意两点的最小值可能在集合内,此时我们考虑重新划分集合,容易发现,可以枚举二进制中的第 \(i\) 位,为 \(0\) 的放进一个集合,为 \(1\) 的放进另一个集合,这样就一定能找到最小值,原因显然
Floyd
常见用法
补充
- 注意重边( \(dp_{x,y}=min(dp_{x,y},z)\) )
题目
-
P6175 无向图的最小环问题
简要思路:见 OI-Wiki 最小环 -
P1730 最小密度路径
简要思路:因为是有向无环图,所以任意两点之间的最小密度路径长度不会超过 \(n\),所以 \(O(n^5)\) 暴力 \(DP\) 即可,再想优化可以参考题解 -
P1613 跑路
简要思路:数据范围小,考虑 \(Floyd\),由于一次可以跑 \(2^k\),所以我们可以预处理出 \(x\) 到 \(y\) 是否有长度为 \(2^k\) 的边(倍增思想),再跑 \(Floyd\),时间复杂度 \(O(n^4)\)
Johnson
常见用法
分层图
常见用法
题目
-
P4568 [JLOI2011] 飞行路线
简要思路:板子题 -
P1266 速度限制
简要思路:对于速度可以建分层图,实现时可以定义 \(dp_{i,j}\) 表示到 \(i\) 时速度为 \(j\) 的最短路,时间复杂度 \(O(V_{max} \times m \times \log m)\)
连通性
常见用法
OI-Wiki 强连通分量
OI-Wiki 双连通分量
OI-Wiki 割点和桥
补充
- 有向图用 \(scc\),无向图用 \(edcc\) 或 \(vdcc\),有时也可以两种图互相转换
- 缩点后会形成一颗树或 \(DAG\),可以从上面找性质,求答案
- 注意 \(scc\) 或 \(vdcc\) 或 \(edcc\) 里面的性质
- 一些题目可以图论建模
题目
-
P5058 [ZJOI2004] 嗅探器
简要思路:题解 -
P3225 [HNOI2012] 矿场搭建
简要思路:题解 -
P1407 [国家集训队] 稳定婚姻
简要思路:题解
基环树
补充
-
基环树找环:
\((1)\) 无向图通过一个动态数组,只有 \(v\) 为该动态数组的最后一位的值时才把 \(u\) 加进去(还需特判 \(u\) 为入环点的情况)
\((2)\) 有向图中,内向图用 \(topo\),外向图转为内向图 -
基环树的处理方法:
\((1)\)在环上找性质
\((2)\)断开环
\((3)\)缩点
题目
-
P2607 [ZJOI2008] 骑士
简要思路:基环树上 \(dp\), 容易发现,我们可以找到环上的一个点,分两种情况:\(u\) 不选和 \(fa_u\) 不选,分别 \(dp\) 即可 -
P4381 [IOI 2008] Island
简要思路:求基环树直径,详见题解 -
P1399 [NOI2013] 快餐店
简要思路:答案应当为删掉环上一条边后的最小直径除以二,详见题解
生成树
最小生成树 (MST)
常见用法
补充
- 写代码时注意区分 \(n,m\)
题目
-
P1991 无线通讯网
简要思路:二分答案,\(MST\) 判断即可 -
P4047 [JSOI2010] 部落划分
简要思路:二分答案,用长度 \(\le x\) 的边建新图,跑 \(MST\),最后判断连通块数量即可。更为优秀做法看题解 -
P1967 [NOIP 2013 提高组] 货车运输
简要思路:容易发现可以建瓶颈生成树,将图化为树,树上倍增或树剖都可以 -
P4951 [USACO01OPEN] Earthquake
简要思路:\(0/1\) 分数规划 \(+ MST\)
dfs 生成树
补充
- \(dfs\) 生成树性质:
1.如果是无向图,只有树边,返祖边
2.如果是有向图,有树边,返祖边,横叉边,前向边
题目
- P11954 「ZHQOI R1」删边
简要思路:构造题,在图上比较难做,可以考虑 \(dfs\) 生成树,则可以删去所有返祖边,形成一棵树,再删去树上的一条边即可,注意细节(菊花图要特殊考虑),具体看题解
第四板块——数据结构
线段树
线段树基础
常见用法
题目
-
P4588 [TJOI2018] 数学计算
简要思路:由于不保证模数是质数,所以用逆元做不行,此时我们可以发现两个操作都可以转换为单点修改,记录第 \(i\) 次询问乘的树,按题意单点修改,查询就输出 \(tr[1]\),即可 -
ABC397 F - Variety Split Hard
思路:
考虑先把数列分成两份,枚举分的位置,对于后半部分直接计算贡献,对于前半部分需要再切分一次,尝试在 \(O(log \times n)\) 的时间内计算贡献。
容易发现可以预处理出 \(fcnt_i\) 表示 \(1\) 到 \(i\) 中切分一次的贡献,注意到,从 \(i-1\) 转移到 \(i\) 的过程中,相当于增加一个断点,所以可以维护一个数列 \(B_i\) 表示断在第 \(i\) 个位置的贡献,需要区间修改和查询最值。
具体地说,记 \(lst_x\) 表示 \(x\) 这个数上一次出现的位置,则从 \(i-1\) 转移到 \(i\) 的过程中,从 \(lst_{A_i}\) 到 \(i-1\) 的位置要加上 \(1\),同时还要新增一个断点,记录它的贡献,具体实现见代码 -
P4513 小白逛公园
简要思路:具体看题解
线段树合并
常见用法
补充
- 注意线段树合并递归到某个节点时,如果 \(A\) 树或者 \(B\) 树上的对应节点为空,便直接返回另一个树上对应节点。如果下一次再次合并的话,就有可能修改这个节点的值,而这个节点可能本来是另一棵已经更新完的线段树。
则线段树合并时可能会修改别的已更新完线段树的值,所以我们需要在更新完第 \(i\) 线段树时及时记录 \(i\) 的答案
题目
P4556 [Vani有约会] 雨天的尾巴 /【模板】线段树合并
简要思路:树上差分转化为单点修改,直接更新线段树,最后 \(dfs\) 合并即可
P3605 [USACO17JAN] Promotion Counting P
简要思路:本题有非常多做法:
- 树状数组。我们可以 \(dfs\) 记录答案,这里有个比较套路的方法:我们可以用全局权值树状数组维护,观察到,\(dfs\) 到 \(u\) 时,前面可能有一些点的贡献会被计算,记为 \(s\),则我们可以先 \(dfs\) 完子树,再查询,贡献就为 \(s+ans_u\),所以我们便可这样计算出答案
- 主席树。查询子树可以通过 \(dfs\) 序转化为区间查询,然后就变成主席树板子
- 线段树合并。由于只有 \(n\) 个点,所以可以动态开点线段树,每次向上合并再查询
扫描线
常见用法
题目
-
P5490 【模板】扫描线 & 矩形面积并
简要思路:板子题 -
P1856 [IOI 1998 ] [USACO5.5] 矩形周长Picture
简要思路:跟矩阵面积并有些像,按 \(x\) 和 \(y\) 分别扫描一次,扫描时横线的贡献等于 \(abs\) (当前总区间覆盖长度 - 上一次总区间覆盖长度),因为每添加一条边,如果没有使总区间覆盖长度发生变化,说明这条边在矩形内部,被包含了,不用计算;如果引起总区间长度发生变化,说明这条边不被包含,应该计算。此外,如果两条扫描线的 \(y\) 相等,那么需要先计算入边,原因显然
第六板块——动态规划
动态规划基础
常见用法
线性DP
题目
P12406 「CZOI-R3」消除序列
思路:
首先发现,交换次数可以归纳为奇数和偶数两种情况,于是定义 \(f_{i,0/1}\) 表示消到 \(B\) 的第 \(i\) 个数时,\(x,y\) 的交换次数为偶数或奇数的答案
第 \(i\) 次循环时,记 \(w_0\) 表示交换次数为偶数的最小代价,\(w_1\) 表示交换次数为奇数的最小代价,则有转移方程:
现在瓶颈在于计算 \(w_0\) 和 \(w_1\)
首先,我们可以计算 \(A_i\) 在第 \(i-1\) 次操作的位置,记为 \(lpos\),然后我们就需要把 \(A_i\) 从 \(lpos\) 移到 \(1\),但这中间可能有数为 \(0\) 导致有部分贡献无需计算,容易发现可以树状数组维护,这里可以用化环为链的方法,但还是需要注意一些边界情况
树形DP
常见用法
补充
- 树形 DP 的状态多样,先考虑经典状态,实在做不了再考虑其他状态,转移方程需仔细推敲
题目
P12734 理解
思路:本题我们可以先定义一个直接出答案的状态:\(f_{u,i}\) 表示以 \(u\) 为根的子树内记忆容量为 \(i\) 的最少时间,特别地,\(f_{u,0}\) 表是以 \(u\) 为根的子树内,不选 \(u\) 的最少时间。则答案应为 \(f_{0,0}\),所以 \(f_u\) 应该不记录 \(u\) 的贡献。
对于状态转移,首先有:
考虑 \(i \in [2,k]\),有三种转移情形:
- \(v\) 不选,此时用于转移的是 \(f_{v,0}\)
- \(v\) 作为根,此时用于转移的是 \(f_{v,k}+r_v\)
- \(v\) 作为 \(u\) 的儿子,此时用于转移的是 \(f_{v,i-1}+t_u\)
但是,我们发现,对于 \(u\) 子树和 \(i\) 的记忆容量,\(u\) 的儿子中可以有最多一个记忆容量为 \(k\),其余都为 \(k-1\)。
这时,我们可以按以下方式处理,就是先算出和再减去 \(v\) 的原贡献加上新贡献
F(i,2,k){
ll s = 0;
for (auto v:go[u]){
s += min(dp[v][0],min(dp[v][k]+ar[v],dp[v][i-1]+br[v]));
}
dp[u][i] = s;
for (auto v:go[u]){
dp[u][i] = min(dp[u][i],s-min(dp[v][0],min(dp[v][k]+ar[v],dp[v][i-1]+br[v]))+min(dp[v][0],min(dp[v][k]+ar[v],dp[v][i]+br[v])));
}
}
最后注意一下多测清空
第十板块——常见技巧
离线处理
简述:把询问离线排序,按一定顺序处理
题目
- P10814 【模板】离线二维数点
简要思路:对询问按 \(k\) 值排序,然后遍历询问,可以直接 \(1∼n\) 加 \(\le que[i].k\) 的点,现在就是要维护 \([l,r]\) 中存在多少个元素 \(\le x\),权值树状数组可以做到,故时间复杂度 \(O(n\times \log n)\)。

浙公网安备 33010602011771号