1. 程式人生 > >POJ 2796:Feel Good 單調棧經典題

POJ 2796:Feel Good 單調棧經典題

題目大意:給出一組數字,求一區間,使得區間元素和乘以區間最小值最大,結果要求給出這個最大值和區間的左右端點。

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 106 - 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
 

 

單調棧: 顧名思義就是在入棧時遵循單調原則,可以求出一個元素向左(或向右)所能擴充套件到的最大長度,並不是說在這一段區間內是單調的,而是保證在該區間內該元素一定是最大或最小; 
單調棧主要是大家要自己列舉,需要找到每個元素最左能擴充套件到那 ,最優能擴充套件到那,當然最小的是你列舉的那個元素。 
我們有如下的性質: 
1. 如果當前元素大於前一元素,那麼前一元素能擴充套件到當前元素,同時說明前面的數對當前元素來說是沒有貢獻的 
2。如果當前元素等於前一元素,那麼前一元素也能擴充套件到當前元素,同時說明前面的元素是可以被忽略的 
3。如果當前元素小於前一個元素,那麼前面至少有一個元素不能擴充套件到當前元素的位置,那麼這些不能繼續擴充套件的元素的存在顯的沒有什麼意義了,不妨刪除它。 
我們得到兩條結論: 
1。一旦一個元素已經進入棧中那麼這個元素向左擴充套件的位置就確定下來了. 
2。一旦一個元素出棧被彈出棧,那麼這個元素向右擴充套件的位置也確定下來了.
 

POJ 2559一樣,把計算矩形的長改為字首和就行。


/* POJ 2796 單調佇列 維護一個單調不降的序列,然後每次遇到比top小的數時進行
 * 出棧操作並且把值更新下
 *
 * */
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <set>
#include <vector>
using namespace std;
const int INF = ~0u>>1;
typedef pair <int,int> P;
#define MID(x,y) ((x+y)>>1)
#define iabs(x) ((x)>0?(x):-(x))
#define REP(i,a,b) for(int i=(a);i<(b);i++)
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define pb push_back
#define mp make_pair
#define print() cout<<"--------"<<endl
typedef long long ll;
ll st[100100],a[100100],sum[100100];
int main(){
	int n;
	while (~scanf("%d", &n)){
		memset(a,0,sizeof(a));
		memset(st,0,sizeof(st));
		for (int i = 1; i <= n; i++){
			scanf("%lld", &a[i]);
			sum[i] += sum[i-1] + a[i];
		}
		int top = 0;
		a[n + 1] = -1;
		ll tmp,ans = -1;
		int l , r;
		for (int i = 1; i <= n + 1; i++){
			while (top != 0 && a[st[top]] > a[i]){
				tmp = a[st[top]] * (sum[i-1] - sum[st[top - 1]]);
				if (tmp > ans){
					ans = tmp;
					l = st[top-1] + 1;
					r = i - 1;
				}
				top --;
			}
			top ++;
			st[top] = i;
		}
		printf("%lldn%d %dn",ans,l,r);
	}
	return 0;
}