NOIP 赛前总结

· · 个人记录

NOIP 赛前总结

by Robbyprogramming

作为一个水平不高的 OIER ,赛前做做总结吧。

知识总结

学到了什么

内容 日期
c++ 语言基础 6/25~7/1
Sort / std::sort 7/2
Binary\ Search 7/8
栈和队列 7/9
递归 7/14
搜索 DFS & BFS 7/16
Merge\ Sort 7/18
Heap / std::priority\_queue 7/22
单调栈,单调队列 8/12
Sparse\ Table 8/16
分块 8/16
线性 Dynamic\ Programming 8/18
序列 DP,区间 DP 8/19
背包 DP 8/21
Binary\ Indexed\ Tree 8/21
Segment\ tree 8/26
KruskalPrim 8/27
Dijkstra 8/27
Topo\ Sort 9/23
Lowest\ Common\ Ancestor 10/3
数学基础 10/9
字符串 Hash 10/11
KMP 10/11
Trie 10/11
概率与期望 10/16

基本学完 NOIP 的重要考点,并通过一系列题目得以落实。

训练的其余时间进行了大量模拟赛,练习时间还算可以。抓的很紧。

赛时策略

比赛的策略很重要。这里以 CSP-S\ 2025 的惨痛教训制定以下策略:

1.仍然先写暴力做法,但花在每一题暴力做法上的时间不可超过 30 分钟。

2.写完暴力再写部分分,不追求正解,但简单题(有时的第一题贪心)可以尝试推出最优解。

3.剩下的时间拿来测试,检查,优化。

考试注意事项

1.分析与过程要再纸上进行推导,读完题目立刻拿笔抄写样例,将精力从屏幕上转移到纸面上,专注于分析本身。

2.写代码是想到就写,调试立马动手,多尝试比只看屏幕不敲代码的代价要低得多。

3.不要瞎探索电脑,出了问题会影响考试心态。

考前准备

1.考前一天晚上 10 点之前睡觉。

2.心无杂念,心平气和,安心,开心。

3.把之前的所有模板敲一遍,写一写 NOIP 以前题目的暴力做法。

4.自信!!!!!!!,NOIP 没有那么难得高分!

学术总结

基础算法

1.贪心

第一题经常就是贪心。这样的策略是很好的,可用于最优解或者假算法偏分。

对于贪心是期望拿到分的。看到简单题就往贪心上去想一想,多手玩,拿纸拿笔。

2.排序

对于和序列位置没有影响,或者可以通过记录序列位置变换问题的,sort 一下说不定有意想不到的结果。

通常和贪心思想一起用。

3.二分

二分搜索

对于有单调性的东西要在序列中查找,二分搜索是 O(n)O(\log n) 的利器。

二分答案

和贪心一样很重要的一个好用的算法。

对于答案有单调性的问题,可以转换为二分搜索答案进行 check 答案可行性的问题。

通常来说,最小值最大最大值最小都常用这样的方式求解。

4.搜索&枚举

写暴力啊!

见到题目就可以打搜索,或者暴力枚举,得部分分。 #### 5.快速幂 数学天天用,无论是数学题还是组合数求逆。 代码很简单,这怎么能不背下来呢。 ### $DP

极为重要的算法和思想。不仅可以将问题转化为分步的最优子问题递推,还在各大更牛的算法有很多很多应用,如倍增DAG最长路 等。

我的 DP 学的并不好,仅仅会最基础的状态设计和转移。

分很多种,不过总结来说都是那样。 题目可用 $DP$ 的条件:重叠子问题,最优子状态,无后效性。 步骤:设计状态,推出转移,初始化递推起点,求得答案。 $DP$ 的经验看个人积累,所以我就不说了,毕竟造诣不深。 ### 数据结构 #### 并查集 很简单的数据结构,再很多算法中都有应用。比如 $Kruskal$。 就是一个用树结构维护的集合,可以做到 $O(\alpha(n))$ 的复杂度查询两个元素是否在同一集合内。非常优秀的算法。 ```cpp int find(int x){return dsu[x]==x?x:dsu[x]=find(dsu[x]);} ``` #### 树状数组 区间上的单点修改和区间查询操作可用其维护,也可扩展为区间修改与单点查询。巧妙地运用了 $lowbit$ 函数。 ```cpp int lowbit(int x){return x&(-x);} ``` #### 线段树 我最喜欢的数据结构。 应用及其广泛。可以对区间修改区间查询高效 $O(\log n)$ 维护。只需要满足结合律。 线段树是真的建了一棵树。节点上存储了需要记录的信息,理解起来其实不难。 #### $ST$ 表 特殊的,对于 $RMQ$ 问题,即区间最值问题(可推广到任何重叠区间不影响答案的问题),做到了 $O(1)$ 查询 $O(n\log n)$ 初始化。用了倍增及 $DP$ 思想。巧妙的利用了重叠区间不影响答案的性质。 ```cpp dp[i][k]=min(dp[i][k-1],dp[i+(1<<(k-1))][k-1]); ``` #### 分块 任意的带修区间性问题都可以用分块相对高效地解决。标记 $\sqrt n$ 一个 $\sqrt n$ 大小的 $tag$ ,每次查询时分别处理左边溢出的,中间 $tag$ 里的,和右边溢出的。复杂度 $O(n\sqrt n)$。 ### 字符串 #### $KMP

字符串匹配经典算法。理解很爽,代码很短,细节很多。

next[i]表示前缀与后缀相同的最大长度。

n 为原串长度,m 为匹配串长度,可以 O(m) 构造 next 数组, 在 O(n) 的时间内完成匹配。

字符串哈希

大可以用 std::unordered\_map 代替。

图论

图论是算法竞赛中的重要部分。

最小生成树(Minimum\ Spanning\ Tree, MST

用于在加权连通图中找到一棵生成树,使得所有边的权重之和最小。

Kruskal

基于贪心算法,将边按权重从小到大排序,依次选择边,若加入后不形成环(用并查集检查),则加入生成树。适用于稀疏图(边少)。用邻接矩阵。

##### $Prim

基于贪心算法,从任意顶点开始,维护一个已选集合,每次选择连接已选集和未选集的最小权重边。适用于稠密图(边多)。用邻接表。

使用优先队列(最小堆)时,O(E \log V)。一般不用堆优化。O(V^2)

最短路(Shortest\ Path

用于求图中两点间的最短路径权重。

堆优化 Dijsktra

贪心算法,适用于非负权图。使用优先队列不断扩展当前最短路径的顶点。不能处理负权。

##### $Floyd

动态规划,求所有点对的最短路径。通过中间点更新距离矩阵,可处理负权,但不能有负环。

$Kruskal$ 和 $Prim$ 选择取决于图密度,$Dijkstra$ 用于丹源非负权最短路,$Floyd$ 适合全源最短路径。 #### 拓扑排序($Topological\ Sort$) 拓扑排序是针对有向无环图($DAG$)的顶点进行线性排序,使得对于任何有向边 $u→v$,$u$ 在排序中都出现在 $v$ 之前。 基于 $BFS$($Kahn$ 算法)或 $DFS$ 实现,本质是不断移除入度为 $0$ 的顶点。 **只能应用于有向无环图($DAG$),有环图无法进行拓扑排序。** $O(V + E)$。 可结合 $DP$ 实现求 $DAG$ 上最长路。 ## 总结 > 蓦然回首,往事并不如烟。 NOIP RP++。