温馨提示(放在最前面)
1.\(UVA\)多组数据。
2.两组数据之间应有空行。
3.所有数据都为0时,\(ans\)=0,\(anl\)=\(anr\)=1(卡了我半小时的坑)。
还有一点于代码中讲。
正文
我们可以发现影响答案的只有两个因素,前缀和就不用说了,用一个数组保存(我亲眼见证隔壁一个一个加\(TLE\)的惨案)。
对于区间内的最小值,可以用单调栈的思想来解决,我们现在以一个值设置为接下来的区间最小值,很容易想到它当然是影响力越大越好(函数单调递增),所以就往前往后安排一个单减栈,在出现一个比它更小的值之后, 它的影响力便烟消云散(让着小朋友)。
总结而来,对于\(a_i\)来说,它作为区间最小值能得到的最大答案便是左边第一个小于它的值的位置+1到右边第一个小于它的值的位置-1,这两个之间的和乘上它自己。
即:
ans=max(ans,a[i]*(b[r[i]]-b[l[i]-1]))
当然,你还不能用\(max\),因为还要找左右端点。
于是我们可以上代码了
#include<iostream>
#include<cstdio>
#include<cstring>
#define int unsigned long long
using namespace std;
int n,a[100050],l[100050],r[100050],anl=1,anr=1,ans,b[100050];
char ch;
int s[100050],top,bb;
inline void read(int &x)
{
x = 0;
while ((ch = getchar()) < 48 || ch > 57);
while (ch >= 48 && ch <= 57)
x = (x << 1) + (x << 3) + ch - 48, ch = getchar();
}
signed main()
{
while(cin>>n){
if (bb) putchar('\n');
else bb = 1;
top=0;
ans=0;
anl=1;
anr=1;
memset(a,0,sizeof(a));
memset(l,0,sizeof(a));
memset(r,0,sizeof(a));
memset(b,0,sizeof(a));
memset(s,0,sizeof(a));
for(int i=1;i<=n;i++){
read(a[i]);
b[i]=b[i-1]+a[i];
}
for(int i=1;i<=n;i++){
while(top&&a[s[top]]>=a[i])top--;
l[i]=s[top]+1;
s[++top]=i;
}
top=0;
s[0]=n+1;
for(int i=n;i>=1;i--){
while(top&&a[s[top]]>=a[i])top--;
r[i]=s[top]-1;
s[++top]=i;
}
for(int i=1;i<=n;i++){
int x=a[i]*(b[r[i]]-b[l[i]-1]);
if(x>ans){
anl=l[i];
anr=r[i];
ans=x;
}
/*
最后一个 温馨提示
本题没有SPJ,因此在ans相等时需要找区间长度更短的
同样短的时候又要找左端点最左边的
*/
if(x==ans&&((r[i]-l[i]<anr-anl)||(r[i]-l[i]==anr-anl)&&l[i]<anl)){
anl=l[i];
anr=r[i];
ans=x;
}
}
cout<<ans<<endl;
cout<<anl<<" "<<anr<<endl;
}
return 0;
}