半年OI一场空,CE文件见祖宗。
A
分析
题面不在描述。
我们手推几组小数据可以得出,
f(1)=1
f(2)=7
f(3)=13
。。。。。。
因为直角三角形一定是要拼成正方形的,所以我们可以近似的看成有4种砖。
1、1×1的方砖。
2、2×2的方砖,没有对角线。
3、2×2的方砖,有一条从左上到右下的对角线。
4、2×2的方砖,有一条从右上到左下的对角线。
我们考虑在一个矩阵上的划分:
显然,我们最后一列只能选择全部使用1×1的方砖。
所以,当我们在最后一列选择全部使用1×1的方砖时,有f[n−1]种情况。
当我们可以选择最后两列时,就有6种情况了。
所以,当我们在最后两列选择时,有f[n−2]×6种情况。
那么我们就可以得到递推式:
fi=fi−1+fi−2×6
直接O(n)过一遍就行了。
代码
1 | /* Headers */ |
B
题面同样不再描述。
我们首先考虑一个最暴力的算法。
首先把读入的数据排序,然后用三重循环判断是否能构成三角形,最后输出面积和。
附一下核心代码:
1 | inline void work(){ |
时间复杂度显然为O(n3),可以得到50pts的好成绩。
然后我们考虑一下优化:显然答案满足二分性质。
首先依旧对于输入数据排序。
然后我们枚举两重循环,接着二分查找能够构成三角形的最大数(临界值)。
查找时统计答案,并且计算面积。
时间复杂度O(n2logn),可以得到70pts的好成绩。
由于二分查找比较简单,这里就不附代码了(雾
继续优化:
这里就要用到单调队列的思想了。
我们在枚举前两个值的时候(设它们分别为a,b),可以发现,对于每一组a,b,都有其对应的临界值c(也就是能够构成三角形的最大数)。
那我们就可以暴力移动临界值c,完成确定临界值时间复杂度O(1)的算法。
把排好序的输入数据想成一个数轴。
也就是说,在枚举过程中,对于当前的a,b,有其对应的临界值,当枚举到a,b+1时,相对应的c也向右移动。
那么我们就可以暴力移动模拟这个过程,用O(1)的时间复杂度解决。
求面积的时候就要用到前缀和的思想了。
我们把求面积公式(海伦公式)拆开,得到一个多项式,然后就直接用前缀和解决其可。
代码(由于Herself32本人太菜了,这里直接附上zhx大爷的std,经过魔改)
1 | /* Headers */ |
C
分析
直接暴力模拟即可。
我们开一个数组直接模拟球位,然后直接把题目中的左右调换,这样更便于操作。
然后观察题意,我们发现,如果激发一个球之后,它将从数组第一个位置消失(弹出),而如果生成球,就要从后面加入数组。
这不就是一个队列嘛!
但是我们这里并不需要循环队列,直接用head
指针操作即可。
再提醒大家几个小小细节:
当球位不够时不能直接添加,而是要激发队首的几个球。
被动和技能不一样,触发被动并不会使球消失。
在生成球的时候,如果球位不够,则激发队首球1次
好了,那么70+行代码也就写出来了。
这里还是直接附上zhx神仙的std(Herself32没来得及重写,TA菜爆了)
代码
1 | /* Headers */ |
后记
最后附一下重新评测的题目地址:
A题:HPOJ1030
B题:HPOJ1031
C题:HPOJ1032
祝大家AK愉快!
v1.5.2