原题链接:拆方块 - 题目 - Daimayuan Online Judge
解题思路:首先我们假设,如果不考虑左右,并且所有方块都等高,那么他们消除需要多久呢?答案是等于高度,因为每一次都只会消去最上面一层。
那么肯定有人要问了,这题目里面每一根柱子也不等高啊?如果一个柱子本身很高,而旁边只有一格,那不是就错了吗?所以我们不难发现,一根柱子的完全消除,还取决于左右两侧柱子的消除时间。
同样不难发现,左右两侧必定在第一次操作就消失。我们可以先从左往右遍历一次,自己的左侧柱子消除时间与自己柱子高度取小值,再从右往左类似的遍历一次,在两次遍历形成的数组取小值即可。
那么又有人要问了,如果假设左右两侧柱子无限多且无限高,另有一根柱子高m,另一根高n,而且m远大于n的话,高度为m的柱子不也是n+1秒就消失了吗?没错,所以这个做法其实是考虑到这个问题的。我们假设那根高度为n的柱子在高度为m的柱子左边。因为是从左往右更新,所以高n的柱子在n次操作后才会消失,而m高的柱子虽然第一次操作时就变成了高度n,但哪怕只考虑m高柱子本身,也只需要n+1次操作就消失,与左侧消失后将其消除的值是完全一致的。而右侧重新往左更新一次,就能让右侧堆对左侧影响了。
最后,输出两个数组中每个值取较小值(就是每个堆从左往右遍历和从右往左遍历得到的两个值取小值)后的最大值。
AC代码:
#include<bits/stdc++.h>
using namespace std;
long long n,h[100010],r[100010],l[100010],maxx=0;
int main(){
cin>>n;
for(int i=1;i<=n;i++) scanf("%lld",&h[i]);//输入
for(int i=1;i<=n;i++) l[i]=min(h[i],l[i-1]+1);//从左往右遍历,考虑左侧堆时间+1和自己高度的较小值为只考虑左堆影响时自己消失的时间
for(int i=n;i>=1;i--) r[i]=min(h[i],r[i+1]+1);//从右往左遍历,考虑右侧堆时间+1和自己高度的较小值为只考虑右堆影响时自己消失的时间
for(int i=1;i<=n;i++) maxx=max(maxx,min(l[i],r[i]));//两次遍历中的较小值就是这个堆实际消失的时间,这当中的最大值就是整个堆消失的时间
cout<<maxx;
return 0;
}