题目描述:对于n个数,求一个区间,使得该区间所有值相加 乘以 该区间最小值 所得值最大
题解:单调栈的应用。题意可以这样说,求以 a[i]为区间最小值 ,求区间所有数的和乘以 a[i]的最大值是多少。这道题,我wa了一天零一夜,终于ac了。。(怪我菜咯。。)
这个过程只要维护个单调栈就行了,首先用一个数组sum去求出前缀和,用lef[i],right[i]存储以a[i]为最小值的区间的范围。求left[i] 和 right[i] 过程相似,简单说下如何求left[i]---》
left[i]就表示a[i]向左延伸能到达的下标,对于栈空,我们直接将 i 入栈,如果非空栈,我们比较栈顶 a[s.top],a[i],如果a[s.top]<a[i],直接入栈,否则出栈,把a[i]向左延伸到s.top
即left[i]=left[s.top],重复操作直至栈空或者a[s.top]<a[i],最后再把i入栈
举个例子:
对于
6
3 1 6 4 5 2 这个样例求left[i],(从1-n编号)
初始化left[i]=i;
1.1入栈,left[1]=1,栈内元素为 1
2.a[2]<a[s.top==1],出栈,向左延伸,left[2]=1,栈内元素为 2
3.a[3]>a[s.top==2],入栈,栈内元素为 2 3
4.a[4]<a[s.top==3],出栈,向左延伸,left[4]=left[s.top==3]=3,栈内元素为 2 4
5.a[5]>a[s.top==3],入栈,栈内元素为 2 4 5
6.a[6]<a[s.top==5],出栈,向左延伸,left[6]=left[s.top==5]=5,此时a[6]<a[s.top==4],出栈,向左延伸,left[6]=left[s.top==4]=3,最后入栈,栈内元素为2 6
同理也可以求出right[i]
然后O(n)枚举i,更新ans=max(sum(Right[i])-sum(Left[i]-1))*a[i])就可以求出了。
下面贴上我的渣渣代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
#include <queue>
#include <stack>
#include <map>
#include <cstring>
#define nloop(a,b,c) for(LL a=b;a>=c;a--)
#define loop(a,b,c) for(LL a=b;a<=c;a++)
#define clr(a,b) memset(a,b,sizeof a)
#define x first
#define y second
#define LL long long
//#define debug
#define maxn 1000005
using namespace std;
LL a[maxn],sum[maxn],Left[maxn],Right[maxn];
void init(LL n)
{
loop(i,1,n)
scanf("%lld",&a[i]);
loop(i,1,n)
sum[i]=sum[i-1]+a[i];
loop(i,1,n)
Left[i]=Right[i]=i;
}
void solve(LL n)
{
stack<LL> s1,s2;
LL ans=-1,l=0,r=0;
loop(i,1,n)
{
if(s1.empty()) s1.push(i);
else
{
while(!s1.empty()&&a[s1.top()]>=a[i])
Left[i]=Left[s1.top()],s1.pop();
s1.push(i);
}
}
nloop(i,n,1)
{
if(s2.empty()) s2.push(i),Right[i]=i;
else
{
while(!s2.empty()&&a[s2.top()]>=a[i])
Right[i]=Right[s2.top()],s2.pop();
s2.push(i);
}
}
loop(i,1,n)
{
//cout<<Left[i]<<" "<<Right[i]<<endl;
LL s=(sum[Right[i]]-sum[Left[i]-1]);
if(a[i]*s>ans)
{
ans=a[i]*s;
l=Left[i];
r=Right[i];
}
}
printf("%lld\n%lld %lld\n",ans,l,r);
}
int main()
{
#ifdef debug
freopen("data.txt","r",stdin);
#endif
LL n;
scanf("%I64d",&n);
init(n);
solve(n);
return 0;
}