这一天是小V 的生日,他收到了朋友们送给他的礼物。
现在,小V 有n 件礼物,他将这n 件礼物排成一排,依次编号为1 到n,每件礼物都有一个满意值w[i]。
现在小V 要从中选取连续编号的礼物(即选取[l, r]内的礼物),使得获得的 happiness 最大。
[l, r]内的 happiness 定义为:
([l, r]内所有礼物满意值的最小值)*([l, r]内所有礼物满意值的和)
小V 想知道他能获得的 happiness 最大是多少,你能帮帮他吗?
数据输入
第一行为一个正整数 n。
第二行为n 个整数 w[1], w[2], …, w[n]
其中:
对于 50%的数据:1<=n<=100, 0<=w[i]<=100
对于 80%的数据:1<=n<=1,000, 0<=w[i]<=1,000
对于 100%的数据:1<=n<=100,000, 0<=w[i]<=10,000
//输入样例 1
3
1 2 3
//输出样例 1
10
//输入样例2
3
2 1 3
//输出样例2
9
暴力做法[O(n^2)]:
#include<iostream>
#define ll long long
using namespace std;
int main(){
ios::sync_with_stdio(0);cin.tie(0);
ll n;
cin>>n;
ll arr[n+1];
for(ll i=1;i<=n;i++){
cin>>arr[i];
}
ll mn,sum,res=-1;
for(int i=1;i<=n;i++){
sum=0;mn=1e18;
for(int j=i;j<=n;j++){
mn=min(mn,arr[j]);
sum+=arr[j];
res=max(sum*mn,res);
}
}
cout<<res<<endl;
return 0;
}
单调栈做法[O(n)]:
#include<iostream>
#include<vector>
#define ll long long
using namespace std;
int main(){
ios::sync_with_stdio(0);cin.tie(0);
ll n,temp,mx=-1;
cin>>n;
ll pre[n+1],arr[n+1+1];
pre[0]=0;
for(ll i=1;i<=n;i++){
cin>>arr[i];
pre[i]=pre[i-1]+arr[i];
}
arr[n+1]=-114514;
/*维护单调上升栈的主要更新操作是当遇到比top更小的元素x时
计算以top为最小值时能取到最大的happiness值,
然后pop掉计算下一个栈顶元素,
直到栈顶元素小于x,
push x完成单次操作;
防止后几个是单调上升元素的情况导致无法计算后几个元素的happiness值,
添加一个非常非常小的数字。*/
vector<ll> v;
for(ll i=1;i<=n+1;i++){
if(v.empty()||arr[i]>=arr[v.back()]){
v.push_back(i);
}
else{
while(!v.empty()&&arr[v.back()]>arr[i]){
ll now=v.back();
v.pop_back();
if(v.empty()){
mx=max(mx,arr[now]*(pre[i-1]));
continue;
}
mx=max(mx,arr[now]*(pre[i-1]-pre[v.back()]));
}
v.push_back(i);
}
}
cout<<mx<<endl;
return 0;
}