B3872 [GESP202309 五级] 巧夺大奖

B3872 [GESP202309 五级] 巧夺大奖

这个题是很典型的贪心题。
首先先根据时间限制,从小到大排序。
按照截止时间依次处理任务,并借助小根堆维护当前已选任务中奖励最小的那个,当任务数量超过当前截止时间时,主动放弃奖励最低的任务,从而确保每一步都能在满足时间约束的前提下获得尽可能高的总奖励。
当需要放弃一个任务时,总是放弃奖励最小的那个,这不会使后续的解变差。可以通过交换论证证明:若最优解中某个时刻保留了奖励更小的任务而放弃了奖励更大的任务,总可以交换这两个任务的选取状态,不会破坏时间约束,且总奖励不减少。

如果从考级来说,没有学到优先队列的话,可以每一步都sort一遍,这样子依旧可以得到全局里面目前最小的元素,虽然时间复杂度不优于优先队列。

  • 优先队列(二叉堆):插入 O(log⁡n),建堆 O(n)
  • 全排序(sort):每次 O(nlog⁡n),n 次就是 O(n^2log⁡n)
#include<bits/stdc++.h>
using namespace std;
const int N = 510;
priority_queue<int,vector<int>,greater<int> >q;
struct node{
    int t,r;
}a[N];
bool cmp(node x,node y)
{
    if(x.t == y.t)return x.r > y.r;
    return x.t < y.t;
}
int main()
{
    int n;
    cin>>n;
    for(int i = 1 ; i <= n ; ++i)cin>>a[i].t;
    for(int i = 1 ; i <= n ; ++i)cin>>a[i].r;
    sort(a+1,a+1+n,cmp);
    int sum = 0,tim = 0;
    for(int i = 1 ; i <= n ; ++i)
    {
//         cout<<a[i].t<<" "<<a[i].r<<endl;
        sum += a[i].r;
        q.push(a[i].r);
        tim++;
        if(tim > a[i].t){
            int now = q.top();
            q.pop();
            sum -= now;tim--;
//             cout<<now<<endl;
        }
    }
    cout<<sum<<endl;
    return 0;
}
posted on 2026-02-11 22:34  钟一一  阅读(100)  评论(0)    收藏  举报