题意
给定n个数,求某段区间的最小值*该段区间所有元素之和的最大值
Sample Input
6
3 1 6 4 5 2
Sample Output
60
3 5
分析
考虑每个数在哪个区间作为最小值。
维护左边和右边第一个比他小的位置。这段的和乘以这个数就是以这个数为最小值时,乘积最大的。
取max即可。
UVA题库注意在最大值相同时,区间长度尽量小,再次区间左端点位置尽量小。并且多组数据(EOF)以及每两组数据之间要输出一个换行符。
我这里没有EOF其他都处理了。
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<stack>
#include<cstring>
using namespace std;
long long n,a[100011],s[100101],l[100011],r[100011],mx,t;
stack<int> st;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
s[i]=s[i-1]+a[i];
}
if(s[n]==0)//到最后一个了还是0
{
cout<<0<<endl<<1<<' '<<1<<endl;
memset(s,0,sizeof(s));
return 0;
}
st.push(0);
a[0]=a[n+1]=-1;
for(int i=1;i<=n;i++)
{
while(!st.empty()&&a[i]<=a[st.top()]) st.pop();
l[i]=st.top();
st.push(i);
}
while(!st.empty()) st.pop();
st.push(n+1);
for(int i=n;i>=1;i--)
{
while(!st.empty()&&a[i]<=a[st.top()]) st.pop();
r[i]=st.top();
st.push(i);
}
long long p1=1,p2=1;
for(int i=1;i<=n;i++)
{
if(mx<a[i]*(s[r[i]-1]-s[l[i]]))
{
mx=a[i]*(s[r[i]-1]-s[l[i]]);
p1=l[i]+1;
p2=r[i]-1;
}
else if(mx==a[i]*(s[r[i]-1]-s[l[i]])&&r[i]-1-l[i]-1<p2-p1)
{
mx=a[i]*(s[r[i]-1]-s[l[i]]);
p1=l[i]+1;
p2=r[i]-1;
}
else if(mx==a[i]*(s[r[i]-1]-s[l[i]])&&r[i]-1-l[i]-1==p2-p1&&p1>l[i]+1)
{
mx=a[i]*(s[r[i]-1]-s[l[i]]);
p1=l[i]+1;
p2=r[i]-1;
}
}
cout<<mx<<endl<<p1<<' '<<p2<<endl;
return 0;
}