首页 > 代码库 > 02day2
02day2
油滴扩展
【问题描述】
在一个长方形框子里,最多有 N(0≤N≤6)个相异的点。在其中任何~个点上放一个很小的油滴,那么这个油滴会一直扩展,直到接触到其他油滴或者框子的边界。必须等一个油滴扩展完毕才能放置下一个油滴。那么应该按照怎样的顺序在这 N 个点上放置油滴,才能使放置完毕后所有油滴占据的总面积最大呢?(不同的油滴不会相互融合)
注:圆的面积公式 V=pi*r*r,其中 r 为圆的半径。
【解题过程】
直接搜索。注意点是:如果一个点在扩展之前已经被一个较大的圆覆盖了,那么在这个点即使扩展也只能扩展到内切为止,对结果没有影响,所以可以不用考虑。
初始得分 100 分。
?
数列
2. 数列 (sequence.pas/c/cpp )
【问题描述】
虽然 msh 长大了,但她还是很喜欢找点游戏自娱自乐。有一天,她在纸上写了一串数字:1,1,2,5,4。接着她擦掉了一个 1,结果发现剩下 1,2,4 都在自己所在的位置上,即 1 在第 1 位,2在第 2 位,4 在第 4 位。她希望擦掉某些数后,剩下的数列中在自己位置上的数尽量多。她发现这个游戏很好玩,于是开始乐此不疲地玩起来……不过她不能确定最多能有多少个数在自己的位置上,所以找到你,请你帮忙计算一下!
【输入】
第一行为一个数 n,表示数列的长度。接下来一行为 n 个用空格隔开的正整数,第 i 行表示数 Ai。
【输出】
一行一个整数,表示擦掉某些数后,最后剩下的数列中最多能有多少个数在自己的位置上,即 Ai=i最多能有多少。
【解题过程】
马上想到对每个数字与位置作差,比如
数列:1 1 2 5 4
位置:1 2 3 4 5
作差:0 1 1 -1 1
从中可以看出,差为负数的数字不用考虑(不管怎么删都不可能到达正确的位置)。
可以发现,我们每在一个位置删去一个数,后面的差值就会减 1。显然,我们最终的答案中的序列中每个数的初始差值排在一起一定是一个最长非降子序列。所以我们只要在差值序列里找最长非降子序列即可。但是这个序列有一定的限制。比如如果要在 1 后面接 3,那么在这两个之间必然要有 2 个元素被删去,所以它们的位置之差应该大于值的差。
以上面的数据为例,
位置 3 的元素 2 如果想要接到位置 1 的元素 1 的后面,中间必然要删去一个数,位置之差 = 3-1,值之差 = 1-0,满足条件,所以可以接上。而位置 2 的元素 1 很明显不能接到位置 1 的元素 1 后面。
但就是因为这个地方导致我不敢写简单明了的动态规划,而是选择了不靠谱的贪心(这什么心态)。初始得分 20 分。
?
黑匣子
【问题描述】
Black Box 是一种原始的数据库。它可以储存一个整数数组,还有一个特别的变量 i。最开始的时候 Black Box 是空的.而 i 等于 0。这个 Black Box 要处理一串命令。
命令只有两种:
ADD(x):把 x 元素放进 Black Box;
GET:i 加 l,然后输出 Black Box 中第 i 小的数。记住:第 i 小的数,就是 Black Box 里的数的按从小到大的顺序排序后的第 i 个元素。例如:
我们来演示一下一个有 11 个命令的命令串。(如下图所示)
现在要求找出对于给定的命令串的最好的处理方法。ADD 和 GET 命令分别最多 200000 个。现在用两个整数数组来表示命令串:
1.A(1),A(2),…A(M):一串将要被放进 Black Box 的元素。每个数都是绝对值不超过2000000000 的整数,M≤200000。
例如上面的例子就是 A=(3,1,一 4,2,8,-1000,2)。
2.u(1),u(2),…u(N):表示第 u(j)个元素被放进了 Blaek Box 里后就出现一个 GET 命令。
例如上面的例子中 u=(l,2,6,6)。输入数据不用判错。
【输入】
第一行,两个整数,M,N。
第二行,M 个整数,表示 A(l)……A(M)。
第三行,N 个整数,表示 u(l)…u(N)。
【输出】
输出 Black Box 根据命令串所得出的输出串,一个数字一行。
【解题过程】
就是动态查询第 k 大的问题。
Treap 什么的早就忘掉了。本来打算直接写个裸的 BST 水个五六十分的,后来想想还是不靠谱。没想到标程就是裸 BST,而且时间完虐其他任何方法。这数据应该说还是太温和了,如果是我出题的话怎么的也要把 BST 卡在 60 分以下吧。
然后考虑用线段树。用 sum 域维护区间内有几个数,每次根据左子树的 sum 与 k 的大小关系来向左或右递归直到找到叶子节点。
但是题目给出的数值的范围是 [-2000000000, 2000000000],如果直接写很明显不实际。但是只有 200000 个数字。这种情况下主要有两种处理方法:
- 动态开辟结点(用到结点时再开辟,但不是用 new,而是用事先定义好的数组中的元素来替代)
- 离散化
我用的是离散化。200000 个数字排个序,那么每个数字都可以与它自己的位置一一对应,数字的大小关系和位置的大小关系是对应的。所以往线段树中插入的不再是数字本身,而是其位置编号。
但是如何知道每个数字的位置编号呢?我用了一个 hash 表,将数值散列到对应的位置编号(用开链法解决冲突)。但事实上这种方法是很低效的,大多数时间浪费在了 hash 上。更好的做法是,将数值在原序列中的位置编号散列到对应的排序后的位置编号。这样就是一一对应的关系了,hash 的复杂度成了真正的 O(1)。
初始得分 20 分。(8 个点超时)原因一是刚才提到的 hash 方法不合理,原因二是线段树的插入写错导致大量的无用递归。
02day2