牛客 小白月赛90. E----小A的任务 (优先队列 (大根堆)+ 枚举) 见识了不开longlong的后果

E-小A的任务_牛客小白月赛90.png


太坑了 在那debug半天 没找到问题 发现是ans的初始值0x3f3f3f3f开的太小了
要开到0x3f3f3f3f3f3f3f3f 等同于long long的 1e19 太坑了
题目里每一个任务的时间上限都是1e9! 所以需要把全部数据开到long long
我本来意识到了要全开成longlong 但看题解作者全开的int
结果!是在定义的时候就写了#define int long long 所有写的int都等同于long long 也算是学到了 以后也这么写

题解

先复习一下stl库里的优先队列
大根堆priority_queue<int> q;
小根堆priority_queue<int, vector<int>, greater<int>>

这个题让你求完成k个b任务所需的最小时间
完成第i个b任务的条件是当前对应的第i个a任务已经完成
举个例子 比如你完成了1 2 3号a任务
这个时候你可以选择完成跳过1号任务去完成2号和3号b任务

(当你需要完成k个b任务 这个时候前k个a任务你是必须要完成的
然后你再从前k个任务中选k个 错)
//刚开始理解的错误思路
实际上你不是从前k个任务选k个b任务 而是在当前已经完成的i个a任务后对应的i个b任务中选k个出来(有可能你想选第n个b任务 就需要将所有a任务都完成)

也就是说有k~n种选择,当i>=k时,每次花费时间为a类任务前i个+b类前i个里面选k个
可以发现,选的k个b任务总和时间一定是前i个中最小的k个时间
那我们可以从1~n号a任务一个一个做,做完第i号a任务后,再将第i号b任务放进优先队列
当优先队列内的b任务总数大于k个我们就可以弹出队列内最大的b任务时间了并记录做到当前k个b任务时的最优解(所用时间最少)
往后每放进一个b任务 弹出来一个最大的b任务
当i=n结束后,就能找到最小时间了
还有些细节部分 在代码里注释

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 1e5 + 10;

LL a[N], b[N];
int n, q;
LL sum, qbsum; //sum存前i个a任务的时间 qbsum存前i个任务内选取k个b任务的最短时间
int ans = 0x3f3f3f3f3f3f3f3f//long long 1e19 太坑了0x3f3f3f3f还不行太小了

void solve()
{
    scanf("%d%d", &n, &q);
    for (int i = 1; i <= n; i ++ ) scanf("%lld", &a[i]);
    for (int i = 1; i <= n; i ++ ) scanf("%lld", &b[i]);


    while (q -- )
    {
        priority_queue<LL> qb; //存k个b任务的完成时间的大根堆
        while(!qb.empty()) qb.pop();
        ans = 0x3f3f3f3f3f3f3f; //每次循环前记得初始化ans 防止上一次答案影响本次答案
        LL k = 0; //clear
        sum = 0; //clear
        qbsum = 0;
        scanf("%lld", &k);
        for (int i = 1; i <= n; i ++ )
        {
            sum += a[i];
            qbsum += b[i];
            qb.push(b[i]);
            if (qb.size() > k)
            {
                LL t = qb.top(); //取出堆内最大的b任务时间
                qb.pop(); //将该最大时间弹出
                qbsum -= t;
            }
            if (qb.size() == k) //当前根堆内b的任务数达到了k个
            {
                ans = min(ans, sum + qbsum); //将当前a任务所需时间+当前完成k个b任务的最小时间 即为当前最优解 与ans比较 将最小值记录进答案
            }
        }
        printf("%lld\n", ans);
        //将所有任务时间全部遍历完后
    }
    return;
}

int main()
{
    solve();

    return 0;
}
posted @ 2024-04-16 15:50  MsEEi  阅读(12)  评论(0)    收藏  举报