http://poj.org/problem?id=2796
题意:给出n个数,问一个区间里面最小的元素*这个区间元素的和的最大值是多少。
思路:只想到了O(n^2)的做法。
参考了http://www.cnblogs.com/ziyi--caolu/archive/2013/06/23/3151556.html的写法,用单调栈可以优化到O(n)。
对于每个元素,维护这个元素向前延伸比它大的有多少个,向后延伸比它小的有多少个。即该元素是处于山谷。
那么如何用单调栈维护这个呢?
首先这个栈是单调递增的,对于当前栈顶的元素top,如果比要进栈的元素now大,那么是top要出栈,那么top出栈后的栈顶元素suftop一定比top小,那么代表着suftop可以向后延伸到top的向后延伸位置,因为入栈元素now一定比top小,那么now可以向前延伸到top向前延伸的位置。
预处理一个前缀和,当元素出栈的时候就可以直接计算了。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <stack> 5 using namespace std; 6 #define N 100010 7 typedef long long LL; 8 struct node { 9 int pre, suf, id; 10 LL num; 11 } p[N]; 12 LL sum[N]; 13 14 void solve(int n) { 15 for(int i = 1; i <= n; i++) { 16 scanf("%lld", &p[i].num); 17 p[i].pre = p[i].suf = 1; p[i].id = i; 18 sum[i] = sum[i-1] + p[i].num; 19 } 20 LL ans = -1; int l, r; // 有0这个坑点 21 stack<node> sta; 22 sta.push(p[1]); 23 for(int i = 2; i <= n; i++) { 24 while(!sta.empty() && sta.top().num > p[i].num) { 25 node top = sta.top(); sta.pop(); 26 if(!sta.empty()) sta.top().suf += top.suf; 27 p[i].pre += top.pre; 28 LL res = sum[top.id + top.suf - 1] - sum[top.id - top.pre]; 29 res *= top.num; 30 if(res > ans) { 31 ans = res; 32 l = top.id - top.pre + 1; 33 r = top.id + top.suf - 1; 34 } 35 } 36 sta.push(p[i]); 37 } 38 while(!sta.empty()) { 39 node top = sta.top(); sta.pop(); 40 if(!sta.empty()) sta.top().suf += top.suf; 41 LL res = sum[top.id + top.suf - 1] - sum[top.id - top.pre]; 42 res *= top.num; 43 if(res > ans) { 44 ans = res; 45 l = top.id - top.pre + 1; 46 r = top.id + top.suf - 1; 47 } 48 } 49 printf("%lld %d %d ", ans, l, r); 50 } 51 52 int main() { 53 int n; 54 while(~scanf("%d", &n)) solve(n); 55 return 0; 56 }