这两天做了一下NOI2014的题目,虽然分数并不理想,但暴露出的问题是挺重要的。
总体来说,这两天的题目都不算太难。
【Day 1】
起床困难综合症:给定初始值x0的取值范围,问经过一系列的位运算后,求得出来的答案的最大值。
考察的算法是二进制运算的位独立性质,以及高位更优性。
显然由于二进制下各位运算是独立的,那么我们每一位取0或取1各模拟一次操作,取最大值。
因为有对初始值取值范围的限制,那么从高位到低位贪心地选1,保证初始值不超过取值范围就可以了。
魔法森林:给定一幅无向图,边上有两个权值ai和bi,选定两个值A和B,一条边可以通过当且仅当A>=ai且B>=bi,问A+B至少为多少时,存在一条从点1到点n的路径。
考察的算法是动态树。
从小到大枚举A,那么随着A的增大,会有新的边加入图中。我们要做的是维护从1到n的路径上bi的最大值最小。这大致上就是一个动态最小生成树的模型。我们需要一个数据结构支持(1)改变树的形态,(2)查询路径上边权最大值。那么用动态树可以在O(log n)时间内解决这两个问题。(关于动态树的总结之后贴)
消除游戏:给定一个填满数字的四连通方格,每一次操作走一条不重叠的路径,使得路径上经过的数字串起来是一个质数或一个回文数,然后这个数字会被“消除”,在它上面的数字会“掉下来”。问可以得到最大得分的操作序列是什么。
这是一道提交答案题。在考场上需要对给定数据的特点仔细分析,设计不同的求解方案,刷出一个更优解。
从数据特点可以发现:
(1) 1、2点需要写完基本的程序。
(2) 3、4、5点需要找最长的质数
(3) 6、7、8、9、10点需要找最长的回文串。
*(4) 第6个点找回文串的优先顺序决定了解的优劣性
*(5) 第10个点是整一条回文串,全都可以消除。
而正确的解法,是将原表格分成若干个12 × 12 的小方格,小方格内的暴力做,定义一个入口与出口,表示小方格之间的转移。
【Day 2】
动物园:给定一个字符串s,求s的每一个前缀,有多少个 前缀的后缀 满足也是s的前缀,且不与s的前缀重叠。
考察的算法是KMP的next数组的灵活运用和倍增思想。
因为next数组的定义是某个前缀的 前缀的后缀,也是s的前缀。满足这一条件的 前缀的后缀 的最长长度是多少。
如果没有“重叠”的限制的话,那么原问题就相当于求沿next指针上跳的层数,dp即可。
如果加上了重叠的限制呢?
那么就要沿着next指针上跳,找到第一个位置j,满足j + j < i(这里的编号是从0到n-1),那么往上跳的所有层数都是满足条件的。
如何找到这个位置?
显然暴力的跳会超时,那么我们可以参照倍增思想,记f[i][j]为从位置j沿next指针往上跳2^i次到达的位置,沿f数组上溯即可。
随机数生成器:给定一套随机序列生成的规则,生成一个包含1~n*m排列的方阵,问从左上角走到右下角形成的序列排序后字典序最小的序列是什么。
考察的算法是贪心。
显然1是一定可以取到的,那么原问题就转化为两个子问题,从左上角到1位置的方阵序列,和1位置到右下角的方阵序列。
(注意存储每个数字的坐标要用short,不然会爆空间。)
当时我写的是splay来维护当前的序列,但这样的时间复杂度是O(n * m * log(n + m))的。反而暴力地打上标记,配合break可以达到O (n * m) 的效果。
实际上可以维护每一列的最高位置与最低位置为多少,直接判断这一个点是否在这一范围内就可以了。