题目:暑假ACM训练的实践与总结
专业班级:信息与计算科学2班
姓名:李雨洁 学号:20164395
2017 年 8 月 25 日
【摘要】 3
1.搜索和图论 4
2.二分查找和单调队列 5
3.树状数组 5
4.总结 6
这个假期的训练从7月31号开始到今天算是接近尾声了。
这次训练首先是复习了搜索和图论的相关内容。对于搜索这方面,分为两部分的内容,dfs,bfs,广度优先搜索(bfs):从初始状态S 开始,利用规则,生成所有可能的状态。构成的下一层节点,检查是否出现目标状态G,若未出现,就对该层所有状态节点,分别顺序利用规则。生成再下一层的所有状态节点,对这一层的所有状态节点检查是否出现G,若未出现,继续按上面思想生成再下一层的所有状态节点,这样一层一层往下展开。直到出现目标状态为止。深度优先搜索(dfs):从初始状态,利用规则生成搜索树下一层任一个结点,检查是否出现目标状态,若未出现,以此状态利用规则生成再下一层任一个结点,再检查,重复过程一直到叶节点(即不能再生成新状态节点),当它仍不是目标状态时,回溯到上一层结果,取另一可能扩展搜索的分支。采用相同办法一直进行下去,直到找到目标状态为止。
而对于图论的相关内容,一是最短路径的三大算法(以及一个算法的优化--spa算法)。另外一种就是最小生成树的两大算法。最短路径的第一个算法就是佛洛依德算法,简单暴力的三重循环查找,要领就是第一重循环代表了中介点,二三层表示起始点,判断路径的大小关系,不断进行更新即可。最短路径的第二个算法是一个速度极其快的算法,但是不能用来处理负环的相关问题,这种算法的基础就是点的松弛技术,是一种单源的最短路径的算法,思路就是以一个点为起点,开始更新,找到到这个点距离最小的点,然后查找这个点能到达的所有点,若距离缩短,则进行更新,更新完之后再进行下一轮的查找。最短路径的第三大算法就是spa算法,这个算法的思路也是更新,距离变小则入栈,出栈更新其他点,如此往复。这个算法的特殊用法就是判断负环是否存在(也就是判断一个点是否入栈次数大于n)。而对于最小生成树的第一个算法,也是用点更新距离,与最短路径第二个算法的不同之处,就是加不加原本的那段距离。
接下来的一段时间我们复习了有关于二分三分以及单调队列的有关内容。二分查找又称折半查找。在一个单调有序的集合中查找元素,每次将集合分为左右两部分,判断解在哪个部分中并调整集合上下界,重复直到找到目标元素。可以优化连续的线性问题时间复杂度log2n。难点在于知道怎么查,查什么(一般比较难的题目会混杂着数学公式的推导,以及证明这个函数的单调性,然后进行二分或者三分的查找),找到mid的含义,理解什么时候l=mid(l=mid+1),什么时候r=mid(r=mid-1),以及什么时候终止(这一点尤为重要,若判断不准,会导致结果的不精确性)。而对于单调栈的相关内容,大概就是满足条件进栈,否则弹出,单调递增头最小,单调递减头最大。常见题型:
1.区间移动,求区间最值。(这种题目的解决方案就是模板加head处理,如果head的值小于区间的左端点,那么head++,一直到head的值属于这个区间,那么这个head下存的东西就是这个区间内的最大(最小)的值)
2.求某个数两边有多少个比他大的(小的)。(这种题目就从两个方向建立单调队列,利用的是单调队列的一个性质,就是存储的是上一个比他大的(小的)值的值或者位置)
3.树状数组
最后我们又进行了为期一周的树状数组和线段树的相关内容的学习。树状数组是一个查询和修改复杂度都为log(n)的数据结构。主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值;经过简单修改可以在log(n)的复杂度下进行范围修改,但是这时只能查询其中一个元素的值(如果加入多个辅助数组则可以实现区间修改与区间查询)。我们对这块知识点十分的陌生,而且树状数组和线段树相关题目的难度较大,无论从理解题目方面亦或是做题方面都比之前来的慢而艰难的多。总的来讲树状数组和线段树都是处理区间问题的一种工具,可以用来优化算法的时间的复杂度,使得一些本该超时的算法得以通过。
对于树状数组而言,它的核心就是lowbit(int x)函数建树,树状数组的元素之间的联系都是建立在这一个简单的位运算上,也就是return x&(-x),然后用add函数和sum函数完成更新和查找的操作,树状数组典型例题:
1.也就是树状数组的使用的初衷,点的更新,区间求和,这类问题就是一种最简单的模板题,用上述三种函数就可以完成,这类问题最典型的就是敌兵布阵。
2.就是用树状数组求逆序数,这种问题一般比较难想到,但一旦想到,处理起来也是一类模板的简单的问题。如果数据范围较大(比如数据大小达到了十亿),需要对数据进行离散化处理(结构体存边的权值以及他的位置,按权值排序,再按位置存到一个新的数组里面,然后用模板即可)。
3.就是区间染色问题,这类问题也算是一种模板,可以扩展到多维,是树状数组的脑洞更新应用类型,这种题的思路就是直接用sum存点被涂色的次数。
4.就是dp的优化问题,这种问题千变万化,但是大都于区间难脱干系。
还有个知识点,就是离散化,离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。通俗的说,离散化是在不改变数据相对大小的条件下,对数据进行相应的缩小。要用到离散化的地方就是当以权值为下标的时候,值太大,数组开不了这么大。 然后把要离散化的每一个数组里面的数映射到另一个值小一点的数组里面去,因为在那个值小一点的数组里本来是没有东西的。
4.总结
总的而言,我很多知识点理解并不好,做题较少,更需要对知识点的理解,还是应该多下功夫。而后,我认为学习比较重要的是知识点的反复,反复是一个十分重要的过程,尤其在编程这种细节极多的项目中。还有感觉到我的自学部分做的并不太好,显得有许多疏漏,有很多东西都没有做到,知识点的遍及面也欠缺了很多。而这一缺陷更需要我在日后的训练中加以弥补,学会通过比赛的正规题目查找到自己学习的知识点还欠缺哪些。
中间打了几场训练赛,我感觉自己做的不好,但是还是有很多收获的。感觉真的打比赛的时候,时间的安排尤为重要。比如第一次训练赛,我先把前两个题目浏览了一遍,但是在看第一题的时候,因为看到它给了图示,心理上就感觉好像特别复杂,然后就先做了第二题,其实今天下午大部分时间都花在了第二题上面。然后第二题一直没有AC,当时思路也比较固定,没有什么突破点,才又回去做了第一题。后来发现第一题要比第二题容易一些,找到规律即可。解完第一题后,又把第二题改了下方法。感觉现在做题还是手忙脚乱,想先从简单的下手,但是自己又往往判断错误。还是需要通过训练积累经验。最近几次的比赛反映出来的,就是模板大致记住,细节处理欠妥,但这是十分致命的,出不了题目是次要的,这种似懂非懂,反而会影响自己的心态,导致往后的比赛无法正常的进行。因此更需要反复,记住其中的细节所在,也就是细节决定成败这句话的含义。
在训练过程中,遇到了很多困难,很多知识自己都感觉很难理解,但是希望自己能坚持下来,不要放弃!加油!