传送门、
题意:给你一段区间,需要你求出(在这段区间之类的最小值*这段区间所有元素之和)的最大值......
单调栈的原理,它就是以某一个值为最小(最大)值,向这个值的两侧延伸,遇到大于它(小于它)的值,就将它延伸的范围扩大,当然,一般来说,要这样做的算法复杂度为o(n^2),但是借助栈这个玩意,维护其单调增(减),就可以在o(n)的时间复杂度解决这个问题。将一元素加入栈时,先判断它是否大于(小于)栈顶元素,若是大于(小于)栈顶元素,加入栈。
#include <iostream>
#include <cstdio>
using namespace std;
#define pi acos(-1)
#define endl '\n'
#define rand() srand(time(0));
#define me(x) memset(x,0,sizeof(x));
#define foreach(it,a) for(__typeof((a).begin()) it=(a).begin();it!=(a).end();it++)
#define close() ios::sync_with_stdio(0);
typedef long long LL;
const int INF=0x3f3f3f3f;
const LL LINF=0x3f3f3f3f3f3f3f3fLL;
//const int dx[]={-1,0,1,0,-1,-1,1,1};
//const int dy[]={0,1,0,-1,1,-1,1,-1};
const int maxn=1e4+5;
const int maxx=100005;
const double EPS=1e-7;
const int MOD=10000007;
typedef pair<int, int>P;
#define mod(x) ((x)%MOD);
template<class T>inline T min(T a,T b,T c) { return min(min(a,b),c);}
template<class T>inline T max(T a,T b,T c) { return max(max(a,b),c);}
template<class T>inline T min(T a,T b,T c,T d) { return min(min(a,b),min(c,d));}
template<class T>inline T max(T a,T b,T c,T d) { return max(max(a,b),max(c,d));}
//typedef tree<pt,null_type,less< pt >,rb_tree_tag,tree_order_statistics_node_update> rbtree;
/*lch[root] = build(L1,p-1,L2+1,L2+cnt);
rch[root] = build(p+1,R1,L2+cnt+1,R2);中前*/
/*lch[root] = build(L1,p-1,L2,L2+cnt-1);
rch[root] = build(p+1,R1,L2+cnt,R2-1);中后*/
long long gcd(long long a , long long b){if(b==0) return a;a%=b;return gcd(b,a);}
#define FOR(x,n,i) for(int i=x;i<=n;i++)
#define FOr(x,n,i) for(int i=x;i<n;i++)
#define W while
int n;
struct node
{
LL sum;//区间和
LL num;//区间最小元素
int begin;//起始位置
int count;//多少个元素
};
node stack[maxx];
int main()
{
close();
// while(cin>>n)
// {
cin>>n;
int top=0;
LL ans=0, tmp, tot;
int l=1,r=1,x,count;
FOr(0,n,i)
{
cin>>x;
tmp=0;
count=0;
while(top>0&&stack[top-1].num>=x)//建立一个单调递增的栈。从第一个元素开始入栈,
//每个元素入栈之前必须先从栈顶开始删除大于或等于它的元素
{
stack[top-1].count+=count;
tot=(stack[top-1].sum+tmp)*stack[top-1].num;
if(tot>ans)
{
ans=tot;
l=stack[top-1].begin;
r=l+stack[top-1].count-1;
}
tmp+=stack[top-1].sum;
count=stack[top-1].count;
--top;
}
stack[top].sum=x+tmp;
stack[top].num=x;
stack[top].begin=i+1-count;
stack[top].count=1+count;
++top;
}
tmp=0;
count=0;
while(top>0)
{
stack[top - 1].count += count;
tot = (stack[top - 1].sum + tmp) *stack[top - 1].num;
if(tot>ans)
{
ans=tot;
l=stack[top-1].begin;
r=l+stack[top-1].count-1;
}
tmp+=stack[top-1].sum;
count=stack[top-1].count;
--top;
}
cout<<ans<<endl<<l<<" "<<r;
// }
}