[UVA1619]Feel Good[DP]

题目链接: [UVA1619]Feel Good[DP]
题意分析:求一个连续区间的最大值。定义:区间最大值 = 区间和 * 区间最小数。

解题思路:根据区间最大值的定义,我们可以枚举每个区间然后进行计算。然而显然是要超时的。这时可以考虑将每个数作为最小值,求出以其为最小值的区间的左值和右值。

以左值的更新为例:当当前值大于等于区间最小值时我们就向左更新,可以发觉,当前值如果比区间最小值大,那么以当前值作为最小值的区间的左值,当前区间肯定也能到达。

eg. 4 3 2 1 4 5 。以1为最小值的区间[1,6]。当更新的时候我们更新到左边的2,以2为最小值的区间为[1,3]这时就可以直接更新到1。这道题要注意下0存在的情况,特判下,另外有多个相同值需要输出最短的区间。

个人感受:这道题和 [HDU1506]Largest Rectangle in a Histogram[dp] 差不多,当时思维被固定了。听他们谈起线段树就以为是线段树才能解。。。。哎,感觉越来越不爱思考了T T
具体代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int MAXN = 1e5 + 111;
typedef long long ll;
int v[MAXN];
ll sum[MAXN], l[MAXN], r[MAXN];

int main()
{
	int n;
	int cnt = 0;
	while( cin >> n )
	{
	    ll ansl = 0, ansr = 0, ansv = -1;
	    memset(sum , 0, sizeof sum);
	    for(int i = 0; i < n; ++i) cin >> v[i], l[i] = r[i] = i;
	    for(int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + v[i - 1]; //记录前n项和
	    for(int i = 0; i < n; ++i) //更新左值
	    {
	        while(v[i] != 0 && l[i] > 0 && v[l[i] - 1] >= v[i])
	           l[i] = l[l[i] - 1];
        }
	    for(int i = n - 1; i >= 0; --i)//更新右值
	    {
	        while(v[i]!= 0 && r[i] < n - 1 && v[r[i] + 1] >= v[i]) //小心为0的情况,这时不进行更新区间
                r[i] = r[r[i] + 1];
        }
        for(int i = 0; i < n; ++i)
        {
            ll temp = (sum[r[i] + 1] - sum[l[i]]) * v[i];
	        if( temp > ansv )
	        {
	            ansv = temp;
	            ansl = l[i] + 1;
	            ansr = r[i] + 1;
            }
            else if(temp == ansv && ansr - ansl > r[i] - l[i]) //注意题目条件
            {
                ansl = l[i] + 1;
                ansr = r[i] + 1;
            }
        }
        if(cnt++) cout << '\n';
        cout << ansv << '\n' << ansl << ' ' << ansr << '\n';
    }
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值