Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 12926 | Accepted: 3617 | |
Case Time Limit: 1000MS | Special Judge |
Description
A new idea Bill has recently developed assigns a non-negative integer value to each day of human life.
Bill calls this value the emotional value of the day. The greater the emotional value is, the better the daywas. Bill suggests that the value of some period of human life is proportional to the sum of the emotional values of the days in the given period, multiplied by the smallest emotional value of the day in it. This schema reflects that good on average period can be greatly spoiled by one very bad day.
Now Bill is planning to investigate his own life and find the period of his life that had the greatest value. Help him to do so.
Input
Output
Sample Input
6 3 1 6 4 5 2
Sample Output
60 3 5
http://poj.org/problem?id=2796
问题概述:一个数列有n个整数,定义一个区间的val为这个区间的最小值*区间所有数之和,求出val最大的区间(任
一),输出这个最大值以及这个区间的左右端
输入样例: 对应输出:
6 60
3 1 6 4 5 2 3 5
传统方法:枚举每一个a[i],向两边循环以求出以a[i]为最小值的所有的区间对应的val,在其中找出一个最大的,复
杂度n²
单调栈的套路:减少大量的重复计算,复杂度为n(用stack比较慢,用数组模拟栈好像快很多)
步骤:
①定义一个结构体,s[i].x表示第i个元素的值a[i]、s[i].m为第i个元素a[i]的下标i、s[i].l和s[i].r分别表示以a[i]为
最小值的最长区间的两端端点(下标)
②定义一个栈t(存入的是结构体),之后保证这个栈里的元素对应的s[i].x递增
③开个sum[],在输入的时候计算前缀和
④遍历每一个数,假设当前为第i个数a[i],如果a[i]比栈顶元素要大,说明s[i].l = i,s[i]入栈,继续遍历,如果a[i]比
栈顶元素小,执行步骤⑤
⑤弹出当前栈顶元素,这个栈顶元素对应的下标k==t.top().m,那么显然s[k].r = i-1,如果弹出后下一个栈顶元素仍
大于当前元素a[i],继续执行步骤⑤,否则执行步骤⑥
⑥我们假设最后一个弹出的元对应的下标为k,那么可以得出s[i].l = s[k].l,好了我们执行步骤④继续遍历
⑦比一比就输出啦
总结:一旦一个元素已经进入栈,那么这个元素向左扩展的位置(s[i].l)就确定下来了,一旦一个元素被弹出栈,
那么这个元素向右扩展的位置(s[i].r)也确定下来了
#include<stdio.h>
#include<stack>
using namespace std;
typedef struct
{
int x;
int l, m, r;
}Point;
Point s[100005];
__int64 sum[100005];
stack<Point> t;
int main(void)
{
int n, i, l, r;
__int64 ans, temp;
while(scanf("%d", &n)!=EOF)
{
sum[0] = 0;
for(i=1;i<=n;i++)
{
scanf("%d", &s[i].x), s[i].m = i;
sum[i] = sum[i-1]+s[i].x;
}
for(i=1;i<=n;i++)
{
s[i].l = i;
while(t.empty()==0 && t.top().x>s[i].x)
{
s[t.top().m].r = i-1;
s[i].l = s[t.top().m].l;
t.pop();
}
t.push(s[i]);
}
while(t.empty()==0)
{
s[t.top().m].r = n;
t.pop();
}
ans = -1;
for(i=1;i<=n;i++)
{
temp = (sum[s[i].r]-sum[s[i].l-1])*s[i].x;
if(temp>ans)
ans = temp, l = s[i].l, r = s[i].r;
}
printf("%I64d\n%d %d\n", ans, l, r);
}
return 0;
}
/*交G++*/