单调栈——POJ - 2796
题目含义
给出一堆数,要你在里面找几个相邻的数
它们的和乘以它们的最小值是这所有数里最大的
输出它们得到的值以及第一个数的坐标和最后一个数的坐标
题目分析
这个式子是:这些数的和 乘以 这些数的最小值
那么如果最小值不变,数的个数是越多越好(因为数都大于零)
那么我们可以考虑根据最小值划分区间,并按最小值从小到大排序
这样的话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\n%d %d\n",ans,ll,rr); return 0; }