poj2796

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

 

题意很好懂,给一串数字,每一个连续子串都有一个最小值,从这个最小值乘以这个子串所有数字的和,然后得到一个结果,求出所有结果里面最大的那个,并且输出相应子串的边界。

 

第一个想法是对每个数都进行一次向两边延拓的操作,直到碰到比它小的数,但是这样时间复杂度是on^2),可能数据比较水,看网上有些人暴力做的,但是刷题就是要提高能力的,有好一点的算法当然要学。

 

这个算法就是单调栈,一次遍历下来两个边界都能确定下来。

 

首先单调栈,很明显就是要满足栈内元素单调递增。当入栈元素的值大于栈顶元素的值,一种是将栈顶元素pop出来直至小于入栈元素,入栈元素继续入栈,还有一种是入栈元素不管,向后扫描直至大于栈顶元素。这里用的是第一个。

 

用两个数组lstnxt分别表示子串的前端和后端,用数组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<a[s[1]]=6,nxt[s[1]]=4-1=3,lst[4]=lst[s[1]]栈顶出栈,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]=62<a[s[2]]=5,nxt[s[2]]=5-1=5lst[4]=lst[s[2]],栈顶出栈,2<a[s[1]]=4nxt[s[1]]=6-1=5lst[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
  • Source Code
    #include <iostream>
    #include <cstdio>
    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))
        {<span style="white-space:pre">	</span>fill(lst,lst+maxn,1);
            fill(nxt,nxt+maxn,1);/*<span style="font-family: Simsun; ">ac的代码里面没有这两行,但是自己多组数据测试下来后面的结果就不对了,加了这两行就对了</span>*/
            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<<ans<<endl<<begin<<" "<<end<<endl;
        } 
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值