题目
思路
这道题的思路总体是扫描,但颇有一番推理的感觉,需要好好理解。
1.根据物理定律,每一段的水位高度h应满足
- 不会高于当前天花板
- 不会低于当前地板
- 向左向右的射线,均不会碰到天花板。(因为水是平的)
2.因此需要求每个h,h满足向左向右延伸都不会碰到天花板的最大值。
3.扫描法。对于每个地方,先求出向左延伸不会碰到天花板的高度h1,再求出向右延伸不会碰到天花板的高度h2,h=min(h1.h2)。
(此举的目的在于,避免一次性计算向左向右,实现降次增倍的效果)
(
–>>
)
代码
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define _for(i,a,b) for (int i = (a); i<(b); i++)
using namespace std;
const int maxn = 1000000 + 1000;
int n, myfloor[maxn], top[maxn], h1[maxn], h2[maxn];
void scan1() {
h1[0] = top[0];
_for(i, 1, n) {
h1[i] = h1[i - 1];
if (h1[i] > top[i]) h1[i] = top[i];
if (h1[i] < myfloor[i]) h1[i] = myfloor[i];
}
}
void scan2() {
h2[n - 1] = top[n - 1];
for (int i = n - 2; i >= 0; i--) {
h2[i] = h2[i + 1];
if (h2[i] > top[i]) h2[i] = top[i];
while (h2[i] < myfloor[i]) h2[i] = myfloor[i];
}
}
int main() {
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int T;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
_for(i, 0, n) scanf("%d", &myfloor[i]);
_for(i, 0, n) scanf("%d", &top[i]);
scan1();
scan2();
int h;
long long ans = 0;
_for(i, 0, n) {
h = min(h1[i], h2[i]);
ans += h - myfloor[i];
}
printf("%lld\n", ans);
}
return 0;
}
本题资源
废话
1.知道了思路以后写的意外顺利。。成功明白,细节多的题目可能很多细节都是为了迎合选手的一般习惯,所以有些题可以不用老管细节,直接往下写即可。
2.ACM/ICPC CERC 2009的官网明明这道题的题目是Cave,到了uva就成了Cav,很神奇。