半年OI一场空,CE文件见祖宗。
A
分析
题面不在描述。
我们手推几组小数据可以得出,
$$f(1)=1$$
$$f(2)=7$$
$$f(3)=13$$
。。。。。。
因为直角三角形一定是要拼成正方形的,所以我们可以近似的看成有4种砖。
1、$1 \times 1$的方砖。
2、$2 \times 2$的方砖,没有对角线。
3、$2 \times 2$的方砖,有一条从左上到右下的对角线。
4、$2 \times 2$的方砖,有一条从右上到左下的对角线。
我们考虑在一个矩阵上的划分:
显然,我们最后一列只能选择全部使用$1 \times 1$的方砖。
所以,当我们在最后一列选择全部使用$1 \times 1$的方砖时,有$f[n-1]$种情况。
当我们可以选择最后两列时,就有6种情况了。
所以,当我们在最后两列选择时,有$f[n-2] \times 6$种情况。
那么我们就可以得到递推式:
$$f_i = f_{i-1}+f_{i-2} \times 6$$.
直接$O(n)$过一遍就行了。
代码
1 | /* Headers */ |
B
题面同样不再描述。
我们首先考虑一个最暴力的算法。
首先把读入的数据排序,然后用三重循环判断是否能构成三角形,最后输出面积和。
附一下核心代码:1
2
3
4
5
6
7
8
9
10
11
12
13inline void work(){
std::sort(num+1,num+n+1);
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
for(int k=j+1;k<=n;k++){
if(test(i,j,k)){
cnt++;
sum=(sum+sec(i,j,k));
}
}
}
}
}
时间复杂度显然为$O(n^3)$,可以得到$ 50pts $的好成绩。
然后我们考虑一下优化:显然答案满足二分性质。
首先依旧对于输入数据排序。
然后我们枚举两重循环,接着二分查找能够构成三角形的最大数(临界值)。
查找时统计答案,并且计算面积。
时间复杂度$O(n^2 \log n)$,可以得到$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愉快!