POJ 2796:Feel Good(单调栈)

Feel Good
Time Limit: 3000MS Memory Limit: 65536K
Total Submissions: 12926 Accepted: 3617
Case Time Limit: 1000MS Special Judge

Description

Bill is developing a new mathematical theory for human emotions. His recent investigations are dedicated to studying how good or bad days influent people's memories about some period of life. 

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

The first line of the input contains n - the number of days of Bill's life he is planning to investigate(1 <= n <= 100 000). The rest of the file contains n integer numbers a1, a2, ... an ranging from 0 to 10 6 - the emotional values of the days. Numbers are separated by spaces and/or line breaks.

Output

Print the greatest value of some period of Bill's life in the first line. And on the second line print two numbers l and r such that the period from l-th to r-th day of Bill's life(inclusive) has the greatest possible value. If there are multiple periods with the greatest possible value,then print any one of them.

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++*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值