带悔贪心

带悔贪心的题目一般都是用小根堆或者大根堆来维护的

大题思想就是说如果做某种抉择的时候,如果后面还有比这个可选的比这个抉择更优的时候

你就先把这个抉择的值存到优先队列里,等下一个抉择的时候选择堆中最优的那个替换掉

https://www.acwing.com/activity/content/problem/content/3798/1/

https://codeforces.com/contest/1526/problem/C2

待更新dp

例题一:传送门

小扣当前位于魔塔游戏第一层,共有 N 个房间,编号为 0 ~ N-1。每个房间的补血道具/怪物对于血量影响记于数组 nums,其中正数表示道具补血数值,即血量增加对应数值;负数表示怪物造成伤害值,即血量减少对应数值;0 表示房间对血量无影响。

小扣初始血量为 1,且无上限。假定小扣原计划按房间编号升序访问所有房间补血/打怪,为保证血量始终为正值,小扣需对房间访问顺序进行调整,每次仅能将一个怪物房间(负数的房间)调整至访问顺序末尾。请返回小扣最少需要调整几次,才能顺利访问所有房间。若调整顺序也无法访问完全部房间,请返回 -1。

示例 1:

输入:nums = [100,100,100,-250,-60,-140,-50,-50,100,150]

输出:1

解释:初始血量为 1。至少需要将 nums[3] 调整至访问顺序末尾以满足要求。

示例 2:

输入:nums = [-200,-300,400,0]

输出:-1

解释:调整访问顺序也无法完成全部房间的访问。

提示:

1 <= nums.length <= 10^5
-10^5 <= nums[i] <= 10^5

这个题是一个带悔贪心,

这个题的题目意思就是说:有一个人在闯魔塔,这个人的初始血量为1,如果魔塔里面的数是为负数代表的是如果他通过会减低a[i]的血量,如果a[i]为正数的话那么会增加a[i]的血量,你在闯魔塔的时候可以把某一层放到最后,问你最少操作多少次能顺利闯完这个魔塔

 

解题思路,就是首先判断能不能闯过去,就是看看所有的加的血量和 和 减的血量和的大小。

其次就是如果你走这个魔塔的时候,血量不足了,然后你肯定是要向前面找一个减的血量最多的魔塔加上,这个可以用小根堆来维护

其次就是在走魔塔的时候能走过去就走过去,并且把扣除血量的那层魔塔加入到小根堆中(从大到小排序的),如果走不过去的话然后

你就取小根堆中扣除血量最大的那个然后移动到最后

 

 

class Solution {
public:
    int magicTower(vector<int>& nums) {
        typedef long long LL;
        int res = 0;
        priority_queue<int> heap;
        LL s1 = 0, s2 = 0;
        for (auto x: nums)
            if (x > 0) s1 += x;
            else s2 -= x;
        if (s1 < s2) return -1;
        LL s = 1;
        for (auto x: nums) {
            s += x;
            if (x < 0) heap.push(-x);
            while (s <= 0) {
                auto t = heap.top();
                heap.pop();
                s += t;
                res ++ ;
            }
        }
        return res;
    }
};

 

例题2:传送门

 

这是这个问题的难点。唯一的区别是在这个版本中n≤200000。只有在两个版本的问题都得到解决时,您才能进行黑客操作。

一行中有n种药剂,药剂1在最左边,药剂n在最右边。每一种药剂将增加你的生命值的ai当饮用。Ai可以是负的,这意味着药水会减少生命值。

一开始你的生命值为0,你将从左往右行走,从第一瓶药水走到最后一瓶。对于每一种药剂,你可以选择喝它或忽略它。你必须确保你的健康总是非负的。

你最多能喝多少药水?

输入
第一行包含一个整数n(1≤n≤200000)——药剂的数量。

下一行包含n个整数a1, a2,…,an(−1e9≤ai≤1e9),表示饮用该药剂后健康状况的变化。

输出
输出一个整数,即在你的生命值不变为负数的情况下你所能饮用的最大药剂数量。

例子

6
4 -4 1 -3 1 -3


5
请注意
在样本中,你可以通过服用药剂1、3、4、5和6来饮用5种药剂。这是不可能喝完所有的6个药水,因为你的健康会在某些时候变得消极

 

这个题和上一个基本上是一样的还是要用一的小根堆维护

    int n; read (n);
    for (int i = 1; i <= n; ++i) read(a[i]);
    int Ans = n, sum = 0;
    for (int i = 1; i <= n; ++i) {
        if (a[i] < 0) q.push (-a[i]);
        sum += a[i];
        while (sum < 0) sum += q.top(), q.pop(), Ans--;
    }
    cout << Ans <<endl;
    return 0;

我当时写的有点垃圾

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=1e6+100;
typedef long long ll;
priority_queue<ll>q;
ll a[maxn];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    } 
    int ans=0;
    ll sum=0;
    for(int i=1;i<=n;i++){
        if(a[i]>=0){
            sum+=a[i];
            ans++;
        }
        else{
            a[i]=-a[i];
            if(sum-a[i]>=0){
                ans++;
                sum-=a[i];
                q.push(a[i]);
                continue;
            }
            if(!q.empty()&&a[i]<q.top()){
                ll p=q.top();
                q.pop();
                sum+=(p-a[i]);
                q.push(a[i]);
            }
        }
    }
    cout<<ans;
    
}

 

posted @ 2021-05-29 16:00  lipu123  阅读(73)  评论(0编辑  收藏  举报