现有一堆边长为1的已经放置好的积木,小明(对的,你没看错,的确是陪伴我们成长的那个小明)想知道当下雨天来时会有多少积水。小明又是如此地喜欢二次元,于是他把这个三维的现实问题简化成二维的问题。设雨量无穷、积木不透水、积木间无缝连接,问在这个二次元的世界里,已放置好的积木会有多少单位的积水量?
第一行包含一个整数T(T≤100),表示接下来的测试样例个数。 每个测试样例有两行组成: 第一行包含一个整数N(N≤1e6),表示积木的列数; 第二行包含N个整数Ai(Ai≤1e6),表示第i列积木的个数。
每个样例输出一行,包含一个整数,为题目所求。
1
11
6 2 2 4 2 0 3 4 4 5 1
19
思路:
从两边开始找能够储存水的地方 从两边开始选择一个比较矮的,往中间找找到比自己高的,计算此时存的水量,然后依次循环。
#include <iostream> #include<stdio.h> #include<math.h> #include<algorithm> #include<string.h> #include<stack> #include<queue> #include<vector> #include<stdlib.h> #include<map> using namespace std; const int INF=(1<<31)-1; typedef long long int LL; LL a[1000010]; LL sum[1000010]; int main() { int n_case; scanf("%d",&n_case); while(n_case--) { LL n,i,j; LL ans=0; memset(a,0,sizeof(a)); scanf("%lld",&n); a[0]=-1; a[n+1]=-1; sum[0]=0; for(i=1; i<=n; i++) { scanf("%lld",&a[i]); sum[i]=a[i]+sum[i-1];// sum 表示从第一个开始到i 积木所占的体积; } LL left=1,right=n; while(left<right) //往中间找, 找到比自己高的 计算体积 ,并且更新左右标记点,直到相遇 { if(a[left] <= a[right]) //以矮的边开始找 { for(i=left+1; i<=right; i++) { if(a[i]>=a[left]) break; } ans=ans+min(a[left],a[i])*(i-left-1)-(sum[i-1]-sum[left]); //计算此时体积 left=i; } else { for(i=right-1; i>=left; i--) { if(a[i]>=a[right]) break; } ans=ans+min(a[right],a[i])*(right-i-1)-(sum[right-1]-sum[i]); right=i; } } printf("%lld\n",ans); } return 0; }