poj 2796 Feel Good

题意: 去掉题干,意思是在一组数里,找到一个以他自己为最小值的范围(向他两边扩展)里,用他的值(最小值)乘以这个范围内数之和。求最小值乘以范围数之和最大化,第一行输出这个最大化的值,第二行输出范围的左右位置。
思路:在做过poj在一片长度不一的矩形里求一个以最矮矩形扩展宽度并乘以宽度得到积的最大化的问题,类比这个我们同样利用构造单调递增栈求出每个点能向一个方向扩展的位置,不同的是这题需要记载这个区域的和,我就用sum数组记载(两个sum数组表示从两个方向扩展的累加和,最后合并,写的很烂……)扩展区域的和,注意,这里遇到前面栈里比自己高的点可以扩展时,sum加上是这个点已经确认sum,而不是只是这个点的权值,因为,前面可以扩展的点可能已出栈,而结果就记录在前面sum里。

#include<cstdio>
#include<stack>
#include<cstring>
using namespace std;
struct Node
{
  long long v;int l,r;
}node[100010];
stack<int> s;
long long sum[100010],sum2[100010],n;
int main()
{
    while(~scanf("%d",&n))
    {
        memset(sum,0,sizeof(sum));
        memset(sum2,0,sizeof(sum2));
        for(int i=1;i<=n;i++) { scanf("%lld",&node[i].v);sum[i]=sum2[i]=node[i].v;}
        node[0].v=node[n+1].v=-1;
        while(!s.empty()) s.pop();s.push(0);
        for(int i=1;i<=n;i++)
        {
            int x=s.top();
            while(node[x].v>=node[i].v)
            {
                sum[i]+=sum[x];
                s.pop();
                x=s.top();
            }
            node[i].l=x+1;
            s.push(i);
        }
        while(!s.empty()) s.pop();s.push(n+1);
        for(int i=n;i>0;i--)
        {
            int x=s.top();
            while(node[x].v>=node[i].v)
            {
                sum2[i]+=sum2[x];
                s.pop();
                x=s.top();
            }
            node[i].r=x-1;
            s.push(i);
        }
        for(int i=1;i<=n;i++)
            sum[i]+=sum2[i]-node[i].v;
        long long maxx=-1;
        int L,R;
        for(int i=1;i<=n;i++)
        {
            long long ans=node[i].v*sum[i];
            if(ans>maxx)
            {
              maxx=ans;
              L=node[i].l,R=node[i].r;
            }
        }
        printf("%lld\n%d %d",maxx,L,R);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值