Feel Good
Time Limit: 3000MS |
|
Memory Limit: 65536K |
Total Submissions: 9748 |
|
Accepted: 2635 |
Case Time Limit: 1000MS |
|
Special Judge |
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
63 1 6 4 5 2
Sample Output
603 5
题意很好懂,给一串数字,每一个连续子串都有一个最小值,从这个最小值乘以这个子串所有数字的和,然后得到一个结果,求出所有结果里面最大的那个,并且输出相应子串的边界。
第一个想法是对每个数都进行一次向两边延拓的操作,直到碰到比它小的数,但是这样时间复杂度是o(n^2),可能数据比较水,看网上有些人暴力做的,但是刷题就是要提高能力的,有好一点的算法当然要学。
这个算法就是单调栈,一次遍历下来两个边界都能确定下来。
首先单调栈,很明显就是要满足栈内元素单调递增。当入栈元素的值大于栈顶元素的值,一种是将栈顶元素pop出来直至小于入栈元素,入栈元素继续入栈,还有一种是入栈元素不管,向后扫描直至大于栈顶元素。这里用的是第一个。
用两个数组lst和nxt分别表示子串的前端和后端,用数组s实现堆栈,并且栈内保存的是入栈元素在原数组中的下表。每个元素入栈时,能够确定他们的前端,即lst[i],然后出栈时确定的是他们的后端,即nxt[i]
例如:
3,1,6,4,5,2
a[6]={0,3 1 6 4 5 2}
3入栈:lst[1]=1,nxt[1]=6,栈内空,直接入栈,s[0]=1;
1入栈:lst[2]=2,nxt[2]=6,栈内非看且1<3,这时候栈顶出栈,同时可以确定 nxt[1]=2-1=1,lst[2]=1,入栈,s[0]=2;
6入栈:lst[3]=3,nxt[3]=3,6>a[s[0]]=1,直接入栈,s[1]=3;
4入栈:4栈顶出栈,4>a[s[0]],入栈,s[1]=4;
5入栈:lst[5]=5,nxt[5]=6,5>a[s[1]]=4,直接入栈,s[2]=5;
2入栈:lst[6]=5,nxt[6]=6,2,lst[4]=lst[s[2]],栈顶出栈,2,nxt[s[1]]=6-1=5,lst[4]=lst[s[1]],栈顶出栈,2>a[s[0]]=1,入栈,s[1]=6;
这个题目其实还是有点问题的,一个是当出现多个最大值,选那个;一个是在实际操作的时候是以一个数为最小值向左右两边延拓,碰到比这个数小的数就停下来,但是如果遇到相等数又怎么办。
Source Code
Problem: 2796 | User: 913000720216 | |
Memory: 2584K | Time: 829MS | |
Language: C++ | Result: Accepted |
#include
#include
using namespace std;
const int maxn=100001;
int n,a[maxn],lst[maxn],nxt[maxn],top=-1,s[maxn];
long long sum[maxn];
void get(int x){
lst[x]=x;nxt[x]=n;
while(top>=0&&a[s[top]]>a[x])
{
nxt[s[top]]=x-1;
lst[x]=lst[s[top]];
top--;
}
}
int main(){
while(~scanf("%d",&n))
{ fill(lst,lst+maxn,1);
fill(nxt,nxt+maxn,1);/*ac的代码里面没有这两行,但是自己多组数据测试下来后面的结果就不对了,加了这两行就对了*/
sum[0]=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
get(i);
}
long long ans=0,begin,end;
for(int i=1;i<=n;i++)
{
long long tmp=(sum[nxt[i]]-sum[lst[i]-1])*a[i];
if(ans<=tmp){
ans=tmp;
begin=lst[i];
end=nxt[i];
}
}
cout<