今天考了一场COCI的比赛,感觉题目没考什么特别难的算法,但是有些题就实现很麻烦。
第一题键盘打字,就是个打表题,打了我好大半天,还好没打错。
第二题一群固执的老人看电视,模拟一下谁去换台,换了什么台就可以过了,注意有循环就输出-1
第三题building,一道卡格式的题,给出每个矩形的左下角右上角坐标,让你勾勒整个透视图的轮廓。我想的是从外围跑一次flood fill,能够接触到的矩形的边就是要画出来的了。然后输出的时候注意下标迭代的顺序。这么一道无聊的题花了我好大半天时间,写了100行才写完。
第四题ranking,就是绑定矩形前缀和,然后利用矩形割补法求一下这个人能“完虐”多少人,多少人能“完虐“他,其他的人总是存在合理的安排顺序的,然后注意一下细节就行了。
第五题堆栈,比较有意思,所有的操作要么是复制一个之前出现过的堆栈,然后把当前操作id放在栈顶,要么复制一个之前的堆栈,然后pop,要么比较两个堆栈有几个公共元素。首先明确模拟肯定没法做,因为每一次复制都会增加O(n)的内存,内存很容易就崩了。模拟一下样例就会发现栈里的元素都是递增的,那么建一棵trie树,把每一操作后新产生的堆栈对应到里面的节点即可,公共元素的操作就显然了,在上面做LCA即可。
第五题。在数轴上有许多城市,相邻两城市距离为1,N辆卡车,每辆途经Ki个城市并给出这Ki个城市。M次询问,每次给出两个城市,问这两辆车迎面相遇多少次,相遇时其中一个车正在掉头或刚好结束旅途不算。N<=100000, M<=300000, Ki之和<300000.
先记录所有掉头的时间并按时间先后排序,对于两辆卡车,若他们在相邻两个事件发生时的左右关系不同,则相遇次数+1,每次询问如果扫描一遍这个数组,可以得50分。
显然可以将询问绑定在其中一个车子的事件上,具体做法是选择Ki较小的绑定。这样做的时间复杂度为Msqrt(N)。证明如下:
若该车的Ki >= sqrtN,只有Kj大于Ki的卡车才会放入,则最多有N / Ki <= sqrtN个询问放在这个事件对应的链表里。
若该车的Ki < sqrtN,则这个车出现在事件数组中的次数=Ki
从这个分析看出最坏的复杂度为(M+N)sqrtN,但是显然这题不可能所有车都处于最坏状态,所以3s应该还是比较宽松的。
具体实现过程中需要扫描事件数组,并实时更新每个车的状态(城市,方向),我自己写得很不科学,最后是按着标程的方法实现的,标程中用map来标记重复的询问,我省略了,加上那个判重大概快300ms。
正常题的解决模式应该是:理解题意,确定方向,对比数据范围,确定大致复杂度,设计算法,实现。
这类题比较特殊,解决模式是:理解题意,可行化,优化,检验复杂度,实现。以后应注意这类问题的操作模式。
#include
#include
#include
#include
#include