Problem E: 积木积水
Description
现有一堆边长为1的已经放置好的积木,小明(对的,你没看错,的确是陪伴我们成长的那个小明)想知道当下雨天来时会有多少积水。小明又是如此地喜欢二次元,于是他把这个三维的现实问题简化成二维的问题。设雨量无穷、积木不透水、积木间无缝连接,问在这个二次元的世界里,已放置好的积木会有多少单位的积水量?
Input
第一行包含一个整数T(T≤100),表示接下来的测试样例个数。 每个测试样例有两行组成: 第一行包含一个整数N(N≤1e6),表示积木的列数; 第二行包含N个整数Ai(Ai≤1e6),表示第i列积木的个数。
Output
每个样例输出一行,包含一个整数,为题目所求。
Sample Input
1
11
6 2 2 4 2 0 3 4 4 5 1
Sample Output
19
解题思路:首先找到最高的那个位置,然后向左右找第二高的位置,把这中间的积水算出来,一直往左右去找。
#include<stdio.h> #include<algorithm> #include<string.h> using namespace std; const int maxn = 1e6+200; typedef long long LL; int a[maxn], bef[maxn], beh[maxn]; int main(){ int cas, n; scanf("%d",&cas); while(cas--){ memset(bef,0,sizeof(bef)); memset(beh,0,sizeof(beh)); scanf("%d",&n); int Maxh = 0, Maxid = 1; for(int i = 1; i <= n; i++){ scanf("%d",&a[i]); if(bef[i-1] < a[i]){ bef[i] = a[i]; }else{ bef[i] = bef[i-1]; } if(a[i]>Maxh){ Maxid = i; Maxh = a[i]; } } int l = 1, r = n; for(int i = 2;i <= n; i++){ if(a[i] <= a[i-1]){ break; }else{ l = i; } } for(int i = n-1;i >= 1; i--){ if(a[i] <= a[i+1]){ break; }else{ r = i; } } if(l >= r){ puts("0"); continue; } for(int i = n; i >= Maxid; i--){ if(beh[i+1] > a[i]){ beh[i] = beh[i+1]; }else{ beh[i] = a[i]; } } LL sum = 0, tmp = 0; int c = 0; int hei = Maxh; beh[r+1] = -1; for(int i = Maxid+1; i <= r; i++){ if(beh[i]!=beh[i+1]){ sum += tmp - (c*(hei-a[i])); hei = a[i]; tmp = 0; c = 0; }else{ tmp += hei - a[i]; c++; } } hei = Maxh; tmp = 0; c = 0; bef[l-1] = -1; for(int i = Maxid-1; i >= l; i--){ if(bef[i]!=bef[i-1]){ sum += tmp - c*(hei-a[i]); hei = a[i]; tmp = 0; c = 0; }else{ tmp += hei - a[i]; c++; } } printf("%lld ",sum); } return 0; }