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 day was. 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 input will contain several test cases, each of them as described below. Consecutive test cases are separated by a single blank line.
The first line of the input file contains n - the number of days of Bill's life he is planning to investigate (1n100000) . 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
For each test case, the output must follow the description below. The outputs of two consecutive cases will be separated by a blank line.
On the first line of the output file print the greatest value of some period of Bill's life.
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 the shortest one. If there are still several possibilities, print the one that occurs first..
Sample Input
6 3 1 6 4 5 2
Sample Output
60 3 5
#include <cstdio> #include <stack> using namespace std; // 原数据 int array[100010]; // left[i]代表在第i个数字左边第一个比其小的数字位置 int left[100010]; // right[i]代表在第i个数字右边第一个比其小的数字位置 int right[100010]; // s[i]代表array[0]+...+array[i] long long s[100010]; int main() { int n; int count = 0; while(scanf("%d", &n) == 1) { // 读入数据 for(int i = 0; i < n; i++) { scanf("%d", &array[i]); left[i] = -1; right[i] = n; if(i == 0) s[i] = array[i]; else s[i] = s[i-1] + array[i]; } // 计算每个数字的左右两边第一个比其小的数字位置 stack<int> my_stack; my_stack.push(0); for(int i = 1; i < n; i++) { while(my_stack.size() > 0 && array[my_stack.top()] > array[i]) { right[my_stack.top()] = i; my_stack.pop(); } my_stack.push(i); } my_stack = stack<int>(); my_stack.push(n-1); for(int i = n-2; i >= 0; i--) { while(my_stack.size() > 0 && array[my_stack.top()] > array[i]) { left[my_stack.top()] = i; my_stack.pop(); } my_stack.push(i); } /* for(int i = 0; i < n; i++) { printf("(%d:left:%d right:%d sum:%lld)\n", array[i], left[i], right[i], s[i]); } printf("\n"); */ // 检查所有元素能够得到的值 long long max_sum = -1; int begin = -1; int end = -1; for(int i = 0; i < n; i++) { long long this_sum; if(array[i] == 0) { this_sum = 0; left[i] = i-1; right[i] = i+1; } else { this_sum = s[right[i]-1] - s[left[i]+1] + array[left[i]+1]; this_sum = this_sum * array[i]; } if(this_sum > max_sum) { max_sum = this_sum; begin = left[i]+1; end = right[i]-1; } else if(this_sum == max_sum) { int t_begin = left[i]+1; int t_end = right[i]-1; if((t_end-t_begin+1) < (end-begin+1)) { end = t_end; begin = t_begin; } else if((t_end-t_begin+1) == (end-begin+1)) { if(t_begin < begin) { begin = t_begin; end = t_end; } } } } if(count > 0) printf("\n"); printf("%lld\n", max_sum); printf("%d %d\n", begin+1, end+1); count++; } return 0; }
这是一道好题。首先观察到数据的范围,n可以达到100000. 用枚举的O(n^2)做会超时。于是想能不能把复杂度降到O(n*logn).
想了半天好像没有办法。想到针对每个数,向其左右扩张,观察何时会有最大值。但是遇到比它小的数不知道是否该停止,因为再遇到其他数可能会有最大值。
这时应该换个角度,以某个数为最小值进行左右扩张。这样,并不会错过最优解,因为最优解总是以某个数为最小值的最优解。
记录每个数向左右扩张的话遇到的第一个比其小的数(对于0不需要左右扩张). 这可以通过一个栈来完成,很巧妙。O(n).
然后枚举所有数,和可以事先计算好,O(n).
总复杂度O(n).