UVa 1442 - Cave

链接:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4188

 

题意:

一个洞穴的宽度由n(n≤1e6)个片段组成。已知位置[i,i+1]处的地面高度pi和顶的高度si(0≤pi<si≤1000),
要求在这个洞穴里储存尽量多的燃料,使得在任何位置燃料都不会碰到顶(但是可以无限接近)。

 

分析:

扫描法。
为了方便起见,下面用“水”来代替题目中的燃料。根据物理定律,每一段有水的连续区间,
水位高度必须相等,且水位必须小于等于区间内的最低天花板高度,因此位置[i,i+1]处的水位满足h≤si,
且从(i,h)出发往左右延伸出的两条射线均不会碰到天花板(即两条射线将一直延伸到
洞穴之外或先碰到地板之间的“墙壁”)。如果这样的h不存在,则规定h=pi(也就是“没水”)。


这样,可以先求出“往左延伸不会碰到天花板”的最大值h1(i),再求“往右延伸不会碰到
天花板”的最大值h2(i),则hi=min{h1(i), h2(i)}。根据对称性,下面只考虑h1(i)的计算:


从左到右扫描。初始时设水位level=s0,然后依次判断各个位置[i,i+1]处的高度。
如果p[i] > level,说明水被“隔断”了,需要把level提升到pi。
如果s[i] < level,说明水位太高,碰到了天花板,需要把level下降到si。
位置[i,i+1]处的水位就是扫描到位置i时的level。
不难发现,两次扫描的时间复杂度均为O(n),总时间复杂度为O(n)。

 

代码:

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 const int UP = 1e6 + 5;
 6 int p[UP], s[UP], h[UP];
 7 
 8 int main(){
 9     int T;
10     scanf("%d", &T);
11     while(T--){
12         int n;
13         scanf("%d", &n);
14         for(int i = 0; i < n; i++) scanf("%d", &p[i]);
15         for(int i = 0; i < n; i++) scanf("%d", &s[i]);
16 
17         int ans = 0, level = s[0];
18         for(int i = 0; i < n; i++){
19             if(p[i] > level) level = p[i];
20             else if(s[i] < level) level = s[i];
21             h[i] = level;
22         }
23 
24         level = s[n-1];
25         for(int i = n - 1; i >= 0; i--){
26             if(p[i] > level) level = p[i];
27             else if(s[i] < level) level = s[i];
28             ans += min(level, h[i]) - p[i];
29         }
30         printf("%d\n", ans);
31     }
32     return 0;
33 }

 

posted @ 2018-01-19 23:48  Ctfes  阅读(116)  评论(0编辑  收藏  举报