数据结构实验题 happiness(暴力做法,单调栈做法)

这一天是小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;
}

单调栈做法:

#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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值