1e5的数据量,一开始想的一层一层遍历高度作差肯定会超时,只能做线性的O(n)扫描。
因此这么想,要算积水,那么肯定有左右两个边界使其成为“凹”型,那么复杂的情况是,这个“凹”型不好找,如何确定整个图形的边界位置,可能凹中带凹,可能几个坑是分开的。这样一来就会不止扫一次才能找到这样图形。
于是,我们可以找到整个图形中的最高点作为图形的分界线,将其分为左右两部分,分开各扫一遍,这样只需O(n)的复杂度。
计算水体积时,从一边向中间扫,找到较大值时,将其记录,找到比记录的值小的值时,与记录的值作差即可得到这个“凹”处的体积。因为有了中央最高处作坑的其中一个固定边界,这样只需要遍历找到另一个边界,即可得到低处与较高处的差值。因为是由内而外的遍历,这样先找到的较大值就会围住比较大值小的低处。必定形成坑。左右遍历后得到的差值之和便是总的积水体积。
#include<stdio.h>
int main()
{
int a[100005],n;
while(scanf("%d",&n)!=EOF)
{
long long Max=0,maxi=0,ans=0;///坑点,地平线是0,所以负数都是坑,不管边缘(第一个和最后一个数)是谁都算凹下去的
for(int i=0; i<n; i++)///最坏情况是2e5*1e5,要用long long
{
scanf("%d",&a[i]);
if(a[i]<0)ans+=-a[i],a[i]=0;///找到一个序列中最大值的位置,然后左右向这个最大值的位置扫
if(a[i]>Max)///每次更新左右扫进去的最大值,如果大于最大值,更新最大值,否则减去,算坑,这样就把其中一个边界都作为最大值,另一个左右的边界是会更新变化的最大值
{
Max=a[i];
maxi=i;
}
}///整个序列的最大值不在计算范围内,因为他作为了边界
int maxx=0;
for(int i=0; i<maxi; i++)
if(a[i]>maxx)maxx=a[i];
else ans+=maxx-a[i];
maxx=0;
for(int i=n-1; i>maxi; i--)
if(a[i]>maxx)maxx=a[i];
else ans+=maxx-a[i];
printf("%lld
",ans);
}
}