【POJ2796】代码,非原创,参考的别人的文章

12 篇文章 0 订阅
4 篇文章 0 订阅
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
/*
    Reference:http://www.cnblogs.com/youngxiao/archive/2010/05/19/1739381.html.THX A LOT TO YOU.
    author:YuXun Lu(A.K.A Kyle Broflovlaski)
    problem:poj2796
    Begin Time:13:00 p.m. 2/18/2012
    End Time: About 4 hours after that
    Test Data:
    6
    3 1 6 4 5 2
    7
    7 6 5 4 3 2 1
    9
    5 4 3 2 1 2 3 4 5
    Summary:
    思路和剪枝真的很重要。
    这道题明显是一个思路上的优化就从TLE变成了ACCEPT
    还有一个重点就是cin和cout在效率方面跟printf和scanf差异巨大。
    以上。
    思路:
    设元素1....n,元素值v[1]...v[n],起始区间s[1]...s[n],结束区间e[1]..e[n]
    本题就是找到以元素i的元素值v[i]为最小值的一个区间。
    因为
    Happy Value : 区间元素值的和*区间最小元素值
    所以区间一定要最长,朴素的搜索一定会爆时间,我们可以采取如下策略剪枝:
    1.对于元素i,读入元素i的元素值v[i],令j = i - 1;
    WHILE (j>0)
    IF v[i] < v[j] THEN
        j = s[j] - 1
    ELSE
        s[i] = j + 1
    ENDIF
    ENDW
    这就获得了v[i]的起始地址,因为如果v[j] > v[i]的话
    那么v[j]对应的区间[s[j]...e[j]]肯定其中所有元素都比v[i]大
    因为v[j]是其中最小的元素,我们把s[j]向左移动一个与s[i]比较,如果小于的话
    那么该元素又成为了新的v[j],如果大于的话移动回来就可以了。
    对于结束地址,也是一样
    WHILE(j <= n+1)
    IF v[i] < v[j] THEN
        j = e[j] + 1
    ELSE
        e[i] = j - 1
    ENDIF
    ENDW
    但是注意到这个算法需要v[i]以1开始
    边界条件为v[0] = -1;v[n+1] = -1;否则根据条件,s[i]和e[i]取不到1和n;
    我们还要维护一个“和表”,其值为
    sum[n] =  v[1] + v[2] + v[3] ... + v[n]
    这个简单,读取完了之后直接加到里面就行了。
    最终输出结果
    res = max(sum[e[i]] - sum[s[i] - 1] ) * v[i] );
    然后再输出s[i],e[i]就可以了。
*/
using namespace std;
const long MAXSIZE = 100010 ;
long long v[MAXSIZE];
long long s[MAXSIZE];
long long e[MAXSIZE];
long long sum[MAXSIZE];

int main()
{
    long n;
 //   freopen("b:\\acm\\poj2796\\input.txt","r",stdin);
//while(cin >> n)
while(scanf("%d",&n) == 1)
{   long long maxv = -1;
    long p,q;
    v[n+1] = -1;
    sum[0] = 0;
    s[0] = 1;
    v[0] = -1;
    for(int i = 1 ; i <= n ; i++)
    {
        int j ;
        //cin >> v[i];
        scanf("%d",&v[i]);
        j = i - 1;
        while( j >= 0 )
        {
            if( v[i] > v[j])
            {
               s[i] = j + 1;
               break;
            }
            else
            //v[i] > v[j]
            {
              j = s[j] - 1;
            }
        }
        sum[i] = sum[i-1] + v[i];
    }
    for(int i = n; i > 0 ; i--)
    {
        int j ;
        j = i + 1;
        while( j <= n + 1)
        {
            if(v[i] > v[j])
            {
                e[i] = j - 1;
                break;
            }
            else
            {
                j = e[j] + 1;
            }
        }
    }

    for(int i = 1; i <= n ; i ++)
    {
        if(v[i]*(sum[e[i]] - sum[s[i]-1]) > maxv)
        {
            maxv = v[i]*(sum[e[i]] - sum[s[i]-1]);
            p = s[i];
            q = e[i];
        }
    }
    //cout << maxv << endl;
    //cout << p << " " << q << endl;
    printf("%I64d\n",maxv);
    printf("%d %d",p,q);
}
   // cout << "Hello world!" << endl;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值