单调栈——POJ

题目含义

给出一堆数,要你在里面找几个相邻的数

它们的和乘以它们的最小值是这所有数里最大的

输出它们得到的值以及第一个数的坐标和最后一个数的坐标

题目分析

这个式子是:这些数的和 乘以 这些数的最小值

那么如果最小值不变,数的个数是越多越好(因为数都大于零)

那么我们可以考虑根据最小值划分区间,并按最小值从小到大排序

这样的话ab相邻区间,a的最小值小于b的最小值

当更新区间时,让b区间的和乘以b代表的最小值,得到b区间的值,与答案做比较,变为更大的那个

再将b区间的范围融入a区间中,表示我们之后要算的是a区间的和乘以a表示的最小值

注意将a[n+1]赋为-1,这样就能够更新总区间的值了

题目代码

#include<stdio.h>
#include<iostream>
#include<math.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=1e5+7;
int n,top,q[maxn],Left[maxn],ll,rr;
LL a[maxn],sum[maxn],ans;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]),sum[i]=sum[i-1]+a[i];
    top=0,ans=-1;
    a[++n]=-1;
    for(int i=1;i<=n;i++){
        if(top==0||a[q[top]]<a[i]){
            q[++top]=i;
            Left[i]=i;///你需要一个数代表这个区间的第一个数的坐标
            continue;
        }
        if(a[i]==a[q[top]])continue;
        while(top>0&&a[q[top]]>a[i]){
            LL temp=(sum[i-1]-sum[Left[q[top]]-1])*a[q[top]];
            if(temp>ans){
                ans=temp;
                rr=i-1;
                ll=Left[q[top]];
            }
            top--;
        }
//        q[++top]=i;
        Left[i]=Left[q[++top]];
        q[top]=i;
    }
    printf("%lld
%d %d
",ans,ll,rr);
    return 0;
}
原文地址:https://www.cnblogs.com/helman/p/11222359.html