题目大意
x=0的正上方有一个水龙头,以每秒1单位体积的速度往下滴水。在x = -1 -3 -5 … left 和 x = 1 3 5 … right 处各有一个隔板,高度已知,求经过了多长时间以后,水会流出最左边的挡板或者是右边的挡板。
样例
input
-1 1
3 5
-3 3
4 3 2 1
-3 5
1 2 2 1 1
0 0
output
6 6 8
解释
在第二组样例中:
三个挡板的高度分别为4 3 2 1,第六秒之后,水会溢出。
思路
首先从0点开始向左寻找左边的最大值maxl
从0点开始向右寻找右边的最大值maxr
比较maxl和maxr的大小
1. maxl < maxr 那么向右寻找第一个大于maxl的值记作maxr 下标记作indexr 这样水就不会漫过(indexr,maxr) 只会向左漫出场景。
2. maxl > maxr 那么向左寻找第一个大于maxr的值记作maxl 下标记作indexl 这样水就不会漫过(indexl,maxl) 只会向右漫出场景。
3. maxl = maxr 同时考虑向左向右漫 取最小的值乘2。
单纯计算向左或者是向右漫出的方法如下:
比如以下值:
index:
-9 -7 -5 -3
val:
1 3 2 4
这个是向左边漫的,那么开始是一个(indexl,maxl)。
使用栈来存储数据,得到这样一个栈:
1
3
4
保证栈是一个栈顶元素到栈尾是从小到达的顺序。
计算的时候val*(index - index)即可
代码
#include<cstdio>
#include<map>
#include<queue>
#include<cstring>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stdlib.h>
#include <math.h>
#include <stack>
#include <set>
using namespace std;
#define LL long long
#define maxn 2005
int d[maxn];
int main()
{
int l,r;
int maxr = 0;
int indexr;
int maxl = 0;
int indexl;
while(scanf("%d%d",&l,&r))
{
maxr = 0;
maxl = 0;
for(int i=(l+1000); i<=(r+1000); i+=2)
{
scanf("%d",&d[i]);
}
//get max val in right
for(int i = (1+1000); i<=(r+1000); i+=2)
{
if(maxr < d[i])
{
maxr = d[i];
indexr = i;
}
}
//get max val in left
for(int i = (l+1000); i<=(-1+1000); i+=2)
{
if(maxl < d[i])
{
maxl = d[i];
indexl = i;
}
}
//printf("(%d : %d) (%d : %d)\n",indexl,maxl,indexr,maxr);
int ans = 0;
if(maxr == maxl)
{
ans = maxr * (indexr - indexl);
//left
int ansl = 0;
stack< pair<int,int> > Sl;
Sl.push(make_pair(d[indexl],indexl));
for(int i = indexl; i>= (l+1000) ; i-=2)
{
if(i==indexl) continue;
while(Sl.top().first < d[i]) Sl.pop();
Sl.push(make_pair(d[i],i));
}
int pre_val = Sl.top().first;
int pre_index = Sl.top().second;
Sl.pop();
while(!Sl.empty())
{
ansl += pre_val*(Sl.top().second - pre_index);
pre_val = Sl.top().first;
pre_index = Sl.top().second;
Sl.pop();
}
//right
int ansr = 0;
stack< pair<int,int> > Sr;
Sr.push(make_pair(d[indexr],indexr));
for(int i = indexr; i <= (r+1000) ; i+=2)
{
if(i==indexr) continue;
while(Sr.top().first < d[i]) Sr.pop();
Sr.push(make_pair(d[i],i));
}
pre_val = Sr.top().first;
pre_index = Sr.top().second;
Sr.pop();
while(!Sr.empty())
{
ansr += pre_val*(pre_index - Sr.top().second);
//printf("%d %d %d \n",ans,pre_val,pre_index);
pre_val = Sr.top().first;
pre_index = Sr.top().second;
Sr.pop();
}
//printf("ansl:%d ansr:%d\n",ansl,ansr);
ans += min(ansl,ansr)*2;
}
//0 --> r find the first val >= maxl
//the water will overflow from left
else if( maxl < maxr )
{
for(int i = (1 + 1000); i<=(r + 1000); i+=2 )
{
if(d[i]> maxl)
{
maxr = d[i];
indexr = i;
break;
}
}
ans = maxl * (indexr - indexl);
//printf("1 and: %d\n",ans);
stack< pair<int,int> > S;
S.push(make_pair(d[indexl],indexl));
for(int i = indexl; i>= (l+1000) ; i-=2)
{
if(i==indexl) continue;
while(S.top().first < d[i]) S.pop();
S.push(make_pair(d[i],i));
}
int pre_val = S.top().first;
int pre_index = S.top().second;
S.pop();
while(!S.empty())
{
ans += pre_val*(S.top().second - pre_index);
pre_val = S.top().first;
pre_index = S.top().second;
S.pop();
}
}
//l <-- 0 find the first val >= maxr
//the water will overflow from right
else if(maxl > maxr)
{
for(int i = (-1 + 1000); i >= (l+1000); i-=2 )
{
if(d[i] > maxr)
{
maxl = d[i];
indexl = i;
break;
}
}
ans = maxr * (indexr - indexl);
//printf("2 and: %d\n",ans);
stack< pair<int,int> > S;
S.push(make_pair(d[indexr],indexr));
for(int i = indexr; i <= (r+1000) ; i+=2)
{
if(i==indexr) continue;
while(S.top().first < d[i]) S.pop();
S.push(make_pair(d[i],i));
}
int pre_val = S.top().first;
int pre_index = S.top().second;
S.pop();
while(!S.empty())
{
ans += pre_val*(pre_index - S.top().second);
printf("%d %d %d \n",ans,pre_val,pre_index);
pre_val = S.top().first;
pre_index = S.top().second;
S.pop();
}
}
//printf("(%d : %d) (%d : %d)\n",indexl,maxl,indexr,maxr);
printf("ans: %d\n",ans);
}
}
/*
-1 1
3 5
-3 3
4 3 2 1
-3 5
1 2 2 1 1
0 0
6 6 8
*/
Hit
此博文只提供思路,不保证最后是否正确。
uva我这里找不到这个题目。