输入样例:
6
3 1 6 4 5 2
输出样例:
60
分析:
舒适值均为正数,先把前缀和整上再说别的;
首先是想到用朴素方法:
枚举每一个数作为最小值然后向左向右搜索比这个最小值大的数的下标,遇到比这个数小的数即跳出,记录最远端的下标,用前缀和计算以此数为最小值时的感受值,对所有结果比较大小,输出最大值即可(我当时写的时候没写前缀和):
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
using namespace std;
const int N=100005;
long long n,ans=0,x[N];
int main(){
scanf("%lld",&n);
for(int i=0;i<n;i++){
scanf("%lld",&x[i]);
}
for(int i=0;i<n;i++){
long long w=x[i],sum=0;
sum+=w;
for(int k=i-1;k>=0;k--){
if(x[k]>=w) sum+=x[k];
else break;
}
for(int k=i+1;k<n;k++){
if(x[k]>=w) sum+=x[k];
else break;
}
ans=max(ans,w*sum);
}
printf("%lld",ans);
return 0;
}
但这样明显时间超限,进而想到用dp优化一下循环
用l和r数组存储下表,如果x[l[i]-1]比x[i]大,那么前面的比x[l[i]-1]大的数必然比x[i]大所以直接更新为
l[i]=l[l[i]-1]
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
using namespace std;
const int N=100005;
long long n,ans=0,x[N];
long long l[N],r[N],qzh[N];
int main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&x[i]);
qzh[i]=qzh[i-1]+x[i];
l[i]=i;
r[i]=i;
}
for(int i=1;i<=n;i++){
long long w=x[i];
while(1){
if(x[i]<=x[l[i]-1])l[i]=l[l[i]-1]; //dp
else break;
}
while(1){
if(x[i]<=x[r[i]+1])r[i]=r[r[i]+1];//dp
else break;
}
ans=max(ans,w*(qzh[r[i]]-qzh[l[i]]+x[l[i]]));
}
printf("%lld",ans);
return 0;
}
这样能过洛谷了,但是数据太大还是过不了:
所以用队列优化:
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
using namespace std;
const int N=100005;
long long ans,x[N];
long long idx,qzh[N],dl[N];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&x[i]);
qzh[i]=qzh[i-1]+x[i];
}
idx=0;
ans=0;
for(int i=1;i<=n+1;i++){
while(idx&&x[dl[idx]]>=x[i]){
if(idx==1) ans=max(ans,x[dl[idx]]*(qzh[i-1]));
else {
ans=max(ans,x[dl[idx]]*(qzh[i-1]-qzh[dl[idx-1]]));
}
idx--;
}
dl[++idx]=i;
}
printf("%lld\n",ans);
return 0;
}