前言
没记错的话,我应该是从9.26号开始停课集训的,不算太早,也不算很晚,这一个多月下来其实还是挺有收获的.
每天上午的模拟考试除了被爆踩的体验之外,也让我接触到,了解到并且学习到一些新的算法和知识,在这个过程中,我发现自己对信息学产生了浓厚的兴趣,这也是我能坚持到今天的最重要的原因.
因为基本上每天都有学习新的算法,新的知识,所以还是比较繁杂的.我大致就分为基本算法,图论,数论,数据结构这四个大的板块来讲.因为有些知识是自学的,可能会有没讲清的地方.基本上每一个专题最后都会有我自己做题时碰到的问题和一些发现的总结.
知识
0x00基本算法
0x01搜索(DFS BFS 剪枝 双向广搜)
搜索想必是联赛考场上最实用的算法之一,"正解想不到,部分分爆搜嘛!".而要想骗到更多分数,不得不了解一下更玄学的搜索技巧.
基础搜索分为DFS(深度优先)和BFS(广度优先).个人发现深搜其实用得更多.
之前一直对数独类搜索题见一道弃一道,因为最近做联赛真题,有一道"靶形数独",不得不学习数独类搜索,于是做了一道很基础的9*9数独,核心就是把行,列,九宫格(九宫格的状态有一个很好的公式:\([(i-1)/3*3]\) \([(j-1)/3+1]\))的状态分别用一个数组记录,类似于八皇后问题,然后一边判断合不合法一边不断深搜下去就行了.
提到"靶形数独"这道题,它是在基础数独上加一点剪枝,不得不感叹剪枝之于搜索,暴力变正解.剪枝说通俗一点就是在搜索的过程中如果发现此次搜索一定不合法或者不是最优解就退出这次搜索,从而大大提高搜索效率.
就拿这道题举例,我们联系一下实际生活中玩数独游戏,我们会选择从可能情况最少的一个格子或者一个行列开始填,这样可以省略掉很多不合法情况的搜索,从而提高搜索效率,这就是一个剪枝.
剪枝怎么剪?这需要我们能够充分挖掘题目的性质,及时排除不合法的情况.(一般的剪枝可以从枚举范围,数据性质,最优解等情况来考虑)
有一道和数独长得差不多的题,叫做"八数码难题",在3*3的正方形中有1~8八个数字,还有一个空格(空格可以与上下左右四个方向交换),给定初始状态,试求最少步数达到目标状态.
首先明确这种求最短路,最少步数等最优解的问题一般会用BFS.实际上这道题普通的BFS就可以过了,但我们发现题目既给了初始状态,又给了目标状态,这不是双向广搜的前提么?
双向广搜其实原理很简单,代码也很好实现.我们知道一般的BFS会用队列queue来实现,把初始状态丢进队列里,每次取出队首来搜索,搜索到合法状态又继续把新搜索到的状态丢进队列里,直到队列为空.
而双向广搜就是把初始状态和目标状态都丢进一个队列里,然后同时扩展状态,直到两边都搜索到了同一个状态.
至于迭代加深搜索和A*搜索我还没来得及学习.
0x02贪心
贪心最核心的就是贪心策略.(当然前提是判断贪心的合法性,这个一般自己举反例来推倒自己的贪心策略),明确了贪心策略之后就很好做题了;
个人对贪心题的理解就是:找贪心策略,处理数据(一般就是sort排序),计算最优解;
基础贪心的贪心策略结合生活实际都能想到(比如有n堆糖果,选择k堆糖果使得选择的糖果总数最大,当然是每次选最多的那一堆啊).
而高难度贪心的贪心策略就不那么好发现了,可能需要你自己手写几个例子,更可能需要你具备良好的数学思维.
拿"国王游戏"举例,你需要拿出两位大臣,分别列出它们按此顺序下的奖赏,然后分别列出它们交换顺序之后的奖赏,然后不断对四个式子进行一大堆的数学操作,最后得到贪心策略;
0x03 分治
快速排序和归并排序都运用到了分治思想;
数论里用得很多的快速幂也是分治思想的产物;(循环实现快速幂的时候,一定要注意给变量赋值1,而不是0)
更难的分治还有基于时间的CDQ分治和基于值域的整体分治
分治里面用得最多的就是二分答案.求解最大值的最小值,最小值的最大值这类问题,十有八九就是二分答案来做.并且一般题目需要求解什么就二分什么;
关于二分答案的模板,我看到了很多写法,但一般知道自己习惯的1种写法就可以了.
二分答案的模板还是很好理解的,就是check函数很难调,一般check函数也没有什么固定的框架,图论题里面它可能以SPFA或Dij为基础(洛谷P1462),其它题里面它又有其它实现的形式,总之重点明确该函数是判断你此次二分值的合法性就可以了.
0x04 动态规划
我一直觉得动态规划是一个思维难度很高,知识点很多(各种类型的DP),但又是最有趣的一个算法;
DP不像贪心(只要考虑贪心策略),它要考虑设置状态,状态转移,边界条件,而往往这些都是难点,这也是DP思维难度高的原因,但只要把这些东西搞定,代码量是真的不会很长;
关于DP我掌握的东西不多,像树形DP,斜率优化DP,状态压缩DP等等这些DP和其它算法,思想的结合与优化,我都不了解,总之我学习DP的路还很长.
但不得不提一下,联赛的话一般都会有一道DP题,近几年好像有考到状压DP.
然后结合每次模拟考试,DP有时虽然不是正解,但能够拿到部分分,而DP作为部分分的时候,一般都是(\(n^2\)以上)的时间复杂度,状态转移方程也不难想,所以这也是我们骗分技巧里的重点内容.
0x10 图论
0x11 最短路
四种求最短路的算法
Floyed:号称最稳定的算法,能够求多源最短路径,但时间复杂度O(\(N^3\))高到不能接受,当数据范围不超过100的时候就考虑吧.
Dijkstra:求单源最短路径,必须要会用Dijkstra+堆优化,时间复杂度O(\(Nlogm\)).
bellman-ford:会SPFA就会这个吧.
SPFA:虽然作为一种经常被出题人卡死的算法,但我们还是有学习的必要的,SPFA+队列优化;
其实最短路问题一般就是用Dijkstra+堆优化和SPFA+队列优化,然后担心后者被卡,所以前者用得更多;
但数据范围不超过100,一定要用Floyed,非常好写,而且很稳定;
我们还可以通过Dijkstra+堆优化求次短路(BZOJ"深入虎穴"),其实就是在求最短路的基础上另加一个存次短路的数组,每次更新松弛最短路时,也要更新次短路;
0x12 最小生成树
两种求最小生成树的算法
Prim:运用到贪心思想和"蓝白点"思想的算法;
Kruskal:运用到了并查集;
最小生成树在题目中会有很多变形,比如有时候是求最大生成树(Kruskal算法,sort排序从大到小就可以了),有时候是求次小生成树;
0x13 差分约束
我所理解的差分约束就是通过题意,挖掘题目中的关系,构造三角不等式,最后跑一遍SPFA;
因为我现在对差分约束的理解还不是很深,做题也不太熟练,所以以后还要继续学习落实这个部分;
0x14 负环
判断负环有两种方法,一是DFS+SPFA(根据从一个点开始DFS,如果最后又回到了这个点,说明存在环来判断),二是BFS+SPFA(根据一个点进出队列超过n次来判断)
0x15 强连通分量
这个知识点最重点的算法就是tarjan算法,不论是强连通分量,缩点,还是求割点,割边都是以tarjan算法为基础来求解的.
缩点就是在求完强连通分量后,把一个强连通分量缩成一个点,然后进行后续操作;
这些后续操作一般就是缩点后重新建图(把不在强连通分量里的边建好),不难证明得到的新图是一个有向无环图,然后题目一般可以转化为求解新图中入度为0的点,或是出度为0的点等等......总之答案就在新图中,我们要善于把题目需要我们求解的东西转化为图的知识来理解;
0x16 二分图
二分图我还只是初学,了解了一下二分图的判定(DFS+黑白染色)和简单的二分图的匹配(匈牙利算法),但其实对于匈牙利算法我好不太理解,只是照着板子打了一道模板题;
但我认为最重要的是二分图的思想和染色的方法;像上面的最小生成树Prim算法就运用到了染色的思想.
0x20 数论
0x21 质数
这一节最重要的就是三个模板
1 O(\(sqrt(n)\))判断质数
2 O(\(n\))线性筛素数
3 O(\(sqrt(n)\))分解质因数
其中通用的就是线性筛法,后续的线性筛欧拉函数其实就是在线性筛素数的模板上增加一个phi数组来存欧拉函数.
线性筛法真的是数论专题里一个很重要的筛法,一定要掌握.
0x22 约数
这一节里最经典的就是求最大公约数的欧几里得算法,两三行代码递归实现;还有一个更相减损术(我发现这个方法反而在难度更高,数据范围很大的题目里有用到,但我还没有去仔细研究过,所以下面给出)
\(gcd(a,b)=gcd(b,a-b)=gcd(a,a-b)\)
提到最大公约数就不得不提到经常与它一起出现的最小公倍数,记住一个性质:
\(gcd(a,b)*lcm(a,b)=a*b\)
0x23 同余
这里有几个很重要的定理和模板.
费马小定理:若p是质数,则对于任意正整数a,有\(a^p≡a\)(mod p)
欧拉定理:若正整数a,n互质,\(a^{φ(n)}≡1\)(mod n)
目前这两个定理我只是用来求乘法逆元,下面会讲到求乘法逆元的几种方法.
欧拉定理的推论:(扩展欧拉定理)
若正整数a,n互质,\(a^b≡a^{bmodφ(n)}\)(mod n)
当a,n不一定互质且b>φ(n)时,有\(a^b≡a^{bmodφ(n)+φ(n)}\)(mod n)
P4139扩展欧拉定理
注意注意,这些定理和公式可能突然全摆在面前会很混淆,真要理解也会有难度,但只要先区分前提条件(是互质还是质数),题目中也一般只要用到公式.
对于这些公式,因为它们的内容很少,所以数论题一般都是几个定理和公式,几个模板结合在一起,不要被吓到了,只要列举出要打哪些公式的模板就可以了(一般都有快速幂出现).
0x30 数据结构
0x31 并查集
并查集的查询操作除了我们常用的路径压缩,还有一种叫做按秩合并的优化方法,但在现阶段的做题中,我们掌握了路径压缩的优化方法已经足够了.
基础的并查集还是不太难,大致分为初始化,合并,查询三个基本操作,都是很好实现的.
而拓展的两类并查集:带权并查集和种类并查集,就有思维难度了.
带权并查集很好理解,就是每个节点或者节点与节点之间是有权值存储一些其他信息的.
这里就不得不说一下并查集实际上是一个森林,我们可以在树中的每条边上记录一个权值,即维护一个数组d,用d[x]保存节点x到父节点fa[x]之间的边权;
每次路径压缩时,除了把每个访问的节点直接指向树根(路径压缩),同时更新这些节点的d值;
洛谷P1196是一道很经典的带权并查集的题目,本题就看作每两艘战舰之间有一条边权为1的边,每一条队列就是一条链(一条链实际上也是一棵树)
种类并查集即对于一个变量x,扩展出它的多个"域"(相当于把一个节点拆成多个节点),故也称为"扩展域"并查集.
洛谷P2024是一道很经典的种类并查集的题目,当然它也能用带权并查集实现.对于题目中的一类动物(即上文中的一个变量),扩展出它的"同类域""捕食域""天敌域"三个"域",即三个种类,注意每次合并前要判断三个域的条件是否都能满足,合并的时候要把三个域都合并.
0x32 树状数组
树状数组的基本用途是维护序列的前缀和.
相比于前缀和数组,树状数组优势在于高效率的单点修改,单点增加(前缀和数组单点修改效率比较低)
树状数组的关键就是lowbit函数,update函数(单点增加),sum函数(前缀和)
注意树状数组的下标绝对不能为0,因为lowbit(0)=0,这样会陷入死循环.
0x33 线段树
线段树是一种基于分治思想的二叉树结构,比树状数组更加通用.
线段树的基本用途是对序列进行维护,支持查询与修改指令;
线段树的应用很灵活,很多操作都是动态的,但关键利用好线段树的叶节点只代表序列一个元素,根节点包含整个区间元素这个性质,不论存储多少信息,从叶节点往上传递就行了.
**保存的数组长度要不小于4*n;**
延迟标记:在学习区间增加的时候第一次接触到,通俗地讲,我们在进行区间增加操作时,如果去更改区间中的每个数(即遍历到每个叶节点),时间复杂度会增加到O(N);延迟标记可以标识该节点曾经被修改,但其子节点尚未被修改(即一个节点被打上延迟标记的同时,它自身保存的信息应该已经被修改完毕)
最后比较一下树状数组和线段树:
树状数组可以实现单点修改和区间求和(如果将序列进行差分,那么还可以实现区间增加和单点询问);
线段树能实现树状数组的所有操作,除此之外,还可以通过标记下传或标记永久化进行区间修改和区间询问;
但树状数组的常数比线段树小,实现也较为简单.
总之,能用树状数组就用树状数组,毕竟大多数情况下都只能用线段树;
0x34 ST表
ST算法用来求解区间最值问题.
ST算法通常用在要多次询问一些区间的最值的问题中,相比于线段树,它的程序实现更简单,运行速度更快,但ST算法不擅长动态修改再询问,即它只能对一个静态的固定的序列进行区间询问最值操作.
ST算法其实也是倍增思想的产物.
0x35 LCA
树上倍增法求LCA主要分为预处理和查询两个部分.
预处理部分主要是DFS遍历求出所有点的深度,相当于把树构造出来.
查询的时候一定要注意倒着for
成长
一个多月的停课,不仅学习到了很多新算法,新知识,上面的陈述肯定无法罗列完全.
但我觉得最重要的还是提高了我的自主学习的能力,培养了我自主学习的习惯,因为我要在老师不会主动来教你的情况下学习这些新算法,肯定要尽己所能,比如推数学公式的时候,一行行式子全都摆在你面前,肯定无法理解,甚至都不知道正确性,于是我发现自己手动在纸上模拟很有帮助.
除了不断提升自己,还要学会利用各种外界渠道,比如翻阅别人的博客笔记,查阅网上书本上的资料,或者是询问身边的同学,这些方法在整个学习生活中都是很有用的.
其次在这一个多月的时间中,我的心态也在不断地调整,态度也在不断地摆正.说实话起初选择停课只有一个很简单的原因---不要参加第一次月考,然后是打算国庆收假完,就回到正常的学习生活中.但就在那十天时间里,如前言所述,我渐渐地对信息学产生了浓厚的兴趣.记得那时候刚停课,高三队爷的讲课也听不懂,考试场场爆零,但就是在这样的艰难处境下,我觉得自己也不该止步于此,我不觉得自己就应该场场垫底,于是我不断地刷题,不断地学习新的知识,就这样,越有压力越有动力去学,越学越觉得有趣.进而走到了今天.
说到心态,不得不说每一场模拟考试对我的影响.每一次考试时,看到题目都是很崩溃的,有些长达几版,有些不知所云,剩下的就完全没有思路,但还记得很多试题的第一版都有大概这样一句话"要发扬传奇神将精神,题目越难,越不要退缩".在这样的考试下,想必也越来越乐观吧(不然该场场自闭了),我现在尚不成熟的暴力骗分技巧就是在这段时期逐渐发展的.
这一次联赛,我对自己也没什么把握,但我觉得最后的成绩能够不辜负自己这一个多月的付出与努力就足够了.怎么说也祝自己2018NOIP rp++吧!
最后,想感谢郡园和郡园的每一位老师为我提供一个这么好的学习平台,给我一次这么好的学习机会;感谢陪我一起起早贪黑的父母;还有高二高三的巨佬学长们,虽然你们大部分的讲题我都悄无声息地掉线了,但也还是要感谢你们的付出;当然还有此刻跟我坐在一个机房里面,与我一起奋斗的每一位cjoier!
祝大家都能够2018 rp++!
原文地址:https://www.cnblogs.com/PPXppx/p/9934666.html