题目大意:给出n个数,求一个区间,使得这个区间的(区间内最小值*区间内元素的和)值最大。
解析:首先如果用暴力的话,我们可以枚举n个数,对每一个数我们先假定它为区间内的最小值,并从这个值开始想左右两侧延伸,如果碰到比这个数大的数则继续向一侧延伸,否则终止,两侧都终止时得到的区间即为以这个数为最小值所能得到的所求值最大的区间,复杂度应为n^2,显然会超时。实际上这个题需要用到单调栈。
关于单调栈和该题,这里直接引用另一篇博客的内容:
http://www.cnblogs.com/ziyi--caolu/archive/2013/06/23/3151556.html
最后附上代码:
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <cstring>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <sstream>
#include <algorithm>
#include <numeric>
#include <functional>
//#include <iomanip.h>
#include <limits.h>
//#include <strstrea.h>
//#include <fstream.h>
#define ll long long
#define ull unsigned long long
//#define int64 long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 5;
int n;
struct node {
int num;
int pre;
int next;
int k;
};
ll s[maxn], t[maxn];
stack<node> st;
int main() {
//freopen("in.txt", "r", stdin);
//freopen("data.out", "w", stdout);
scanf("%d", &n);
ll ans = -100, sum = -100;
s[0] = 0;
for (int i = 1; i <= n; i++) {
scanf("%I64d", &t[i]);
if (i == 1)
s[i] = t[i];
else
s[i] = s[i - 1] + t[i];
}
node tmp;
tmp.num = t[1];
tmp.next = tmp.pre = 1;
tmp.k = 1;
st.push(tmp);
int x, y;
for (int i = 2; i <= n; i++) {
node tmp1;
tmp1.num = t[i];
tmp1.next = tmp1.pre = 1;
tmp1.k = i;
while (!st.empty() && tmp1.num <= st.top().num) {
tmp = st.top();
st.pop();
if (!st.empty())
st.top().next += tmp.next;
tmp1.pre += tmp.pre;
ans = tmp.num * (s[tmp.k + tmp.next - 1] - s[tmp.k - tmp.pre]);
if (ans >= sum) {
sum = ans;
x = tmp.k - tmp.pre + 1;
y = tmp.k + tmp.next - 1;
}
}
st.push(tmp1);
}
while (!st.empty()) {
tmp = st.top();
st.pop();
if (!st.empty())
st.top().next += tmp.next;
ans = tmp.num * (s[tmp.k + tmp.next - 1] - s[tmp.k - tmp.pre]);
if (ans >= sum) {
sum = ans;
x = tmp.k - tmp.pre + 1;
y = tmp.k + tmp.next - 1;
}
}
printf("%I64d\n%d %d", sum, x, y);
//fclose(stdin);
//fclose(stdout);
return 0;
}
需要注意的是此题读入数据很大,用cin会超时,所以用scanf。