链接
题意
给出一个长度为n的序列(1 <= n <= 100000),某个区间的权值为该区间内元素和乘以区间内元素最小值,求全职最高的区间和对应的权值,多个解输出任意值。
题解
首先说一下,UVa的数据有问题,建议直接做POJ的2796。
是一道简单题,对每个元素找到以该元素为最小元素的最长区间即可,利用单调栈可以迅速算出每个元素左右端首个小于自身的元素下标,然后遍历枚举即可。
代码
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long lint;
#define maxn (100010)
#define left lleft
#define right rright
int a[maxn], _top, left[maxn], right[maxn];
pair<int, int> _stack[maxn];
lint sum[maxn];
int main()
{
//freopen("1619.txt", "w", stdout);
int n, first = 1;
while(cin >> n)
{
if(first) first = 0;
else cout << endl;
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
sum[0] = 0;
for(int i = 1; i <= n; i++)
sum[i] = sum[i - 1] + a[i];
_top = 0;
for(int i = 1; i <= n; i++)
{
while(_top > 0)
{
if(_stack[_top].first < a[i])
break;
_top--;
}
if(!_top) left[i] = 0;
else left[i] = _stack[_top].second;
++_top;
_stack[_top] = make_pair(a[i], i);
}
_top = 0;
for(int i = n; i >= 1; i--)
{
while(_top > 0)
{
if(_stack[_top].first < a[i])
break;
_top--;
}
if(!_top) right[i] = n + 1;
else right[i] = _stack[_top].second;
++_top;
_stack[_top] = make_pair(a[i], i);
}
lint o = -1, cmp;
int l, r;
for(int i = 1; i <= n; i++)
{
cmp = (sum[right[i] - 1] - sum[left[i]]) * a[i];
if(cmp > o) { o = cmp; l = left[i] + 1; r = right[i] - 1; }
}
cout << o << endl;
cout << l << " " << r << endl;
}
return 0;
}