首页 > 其他分享 >【每日一题】补档 CF730I. Olympiad in Programming and Sports | 反悔贪心 | 困难

【每日一题】补档 CF730I. Olympiad in Programming and Sports | 反悔贪心 | 困难

时间:2024-04-06 15:00:34浏览次数:18  
标签:last idx val int 编程 Programming 补档 Sports vec

题目内容

原题链接

给定 n n n 个学生,第 i i i 个学生的编程能力为 a i a_i ai​ ,运动能力为 b i b_i bi​ 。

现在要选择 p p p 个学生进入编程队, s s s 个学生进入运动队,每个学生只能加入一个队。

问加入两个队的 p + s p+s p+s 个学生的能力之和最大是多少。

注意: 加入运动队的学生能力为其运动能力,加入编程队的学生能力为其编程能力。

数据范围

  • 2 ≤ n ≤ 3000 2\leq n\leq 3000 2≤n≤3000
  • 1 ≤ a i , b i ≤ 3000 1\leq a_i,b_i\leq 3000 1≤ai​,bi​≤3000
  • p + s ≤ n p+s\leq n p+s≤n

题解

我们考虑这么一个问题:假设当前已经选择过了 p + s p+s p+s 个学生,其中 p p p 个加入了编程队, s s s 个加入了运动队。

但是,现在存在一个没有加入任意一个队伍的学生,他的编程能力大于编程队中某个学生的编程能力。

这符合现状吗?显然是不符合的,所以我们可以考虑先凑齐一个队伍。

即我们将所有学生按照其编程能力从大到小排序,选择前 p p p 个学生加入编程队。之后,我们来考虑选择 s s s 个学生加入运动队。

我们的目的是使得所有的学生在对应队伍的能力值之和最大。

所以接下来我们选择运动队的学生,有两种选择方式:

  • 直接选择当前既不在编程队,也不在运动队中的,运动能力最高的学生,加入运动队
  • 从编程队中,选择一个 b i − a i b_i-a_i bi​−ai​ 最大的学生,将其从编程队转移到运动队,然后从既不在编程队,也不在运动队中的,编程能力最高的学生,加入编程队。

这样始终保证编程队的人数为 p p p ,每次选择都使得运动队的人数加 1 。

每次我们选择上述两种方式中,使得总能力变得更大的一种选择。

因此需要维护三个堆:

  • 在编程队中的学生,维护一个 b i − a i b_i-a_i bi​−ai​ 的大根堆
  • 既不在编程队,也不在运动队中的学生,维护一个 a i a_i ai​ 的大根堆
  • 既不在编程队,也不在运动队中的学生,维护一个 b i b_i bi​ 的大根堆

当然,介于这题的数据范围,完全可以两层循环 O ( n 2 ) O(n^2) O(n2) 来解决,从而不用麻烦地维护三个堆。

时间复杂度: O ( n log ⁡ n ) O(n\log n) O(nlogn)

代码

#include <bits/stdc++.h>
using namespace std;

struct Node1 {
    int val;
    int idx;
    Node1(int val, int idx): val(val), idx(idx) {}
    bool operator< (const Node1& A) const {
        return val < A.val;
    }
};

struct Node2 {
    int val;
    int idx;
    Node2(int val, int idx): val(val), idx(idx) {}
    bool operator< (const Node2& A) const {
        return val < A.val;
    }
};

void solve() {
    int n, p, s;
    cin >> n >> p >> s;

    vector<int> vp(n), vs(n);
    vector<array<int, 3>> vec(n);
    for (int i = 0; i < n; ++i) { cin >> vp[i]; vec[i][0] = vp[i]; } ;
    for (int i = 0; i < n; ++i) { cin >> vs[i]; vec[i][1] = vs[i]; vec[i][2] = i; };

    sort(vec.begin(), vec.end(), [](const auto& A, const auto& B) {
        return A[0] > B[0];
    });

    vector<int> vis(n, 0);

    priority_queue<Node1> heap_p2s;
    int ans = 0;
    for (int i = 0; i < p; ++i) {
        ans += vec[i][0];
        heap_p2s.emplace(vec[i][1] - vec[i][0], vec[i][2]);
        vis[vec[i][2]] = 1;
    }

    priority_queue<Node2> last_p, last_s;
    for (int i = p; i < n; ++i) {
        last_p.emplace(vec[i][0], vec[i][2]);
        last_s.emplace(vec[i][1], vec[i][2]);
    }

    // 两种选择:
    // 要么从 p2s 队列中选一个 s - p 最大的,转移到 s 队列中,然后选一个编程能力最大的
    // 要么直接从剩下的部分选一个运动能力最大的
    // 两者选一个

    for (int c = 0; c < s; ++c) {
        while (!last_p.empty() && vis[last_p.top().idx]) last_p.pop();
        while (!last_s.empty() && vis[last_s.top().idx]) last_s.pop();

        // 方案1,选一个 p2s 中 s-p 最大的
        if (!heap_p2s.empty()) {
            auto top = heap_p2s.top();
            int v1 = top.val + last_p.top().val;
            int v2 = last_s.top().val;
            if (v1 <= v2) {
                auto top2 = last_s.top();
                vis[top2.idx] = 2;
                ans += v2;
            } else {
                auto top2 = last_p.top();
                vis[top.idx] = 2;
                vis[top2.idx] = 1;
                heap_p2s.pop();
                heap_p2s.emplace(vs[top2.idx] - top2.val, top2.idx);
                ans += v1;
            }
        } else {
            // 方案2,选一个运动能力最大的
            auto top = last_s.top();
            vis[top.idx] = 2;
            ans += top.val;
        }
    }

    cout << ans << "\n";
    for (int i = 0; i < n; ++i) {
        if (vis[i] == 1) cout << i + 1 << " ";
    }
    cout << "\n";
    for (int i = 0; i < n; ++i) {
        if (vis[i] == 2) cout << i + 1 << " ";
    }
    cout << "\n";
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int T = 1;
    //cin >> T;
    while (T--) {
        solve();
    }

    return 0;
}

标签:last,idx,val,int,编程,Programming,补档,Sports,vec
From: https://blog.csdn.net/weixin_43900869/article/details/137408492

相关文章

  • 「补档」胡乱写写科幻·第二弹·「虚假的快乐」
    不难发现,人情绪的本质从来不是事实是怎样,而是你怎样去认知。所以愚蠢的人总是能获得简单又纯粹的幸福,陷入一片「虚假的快乐」之中,而智者却因为洞察了一切而总是陷入痛苦之中。「具有这种犀利眼光,能够看清真相的人,可以任意支配整个世界及其知识财富。作为一个始终具有善于观察并......
  • KYOCERA Programming Contest 2021(AtCoder Beginner Contest 200)
    题目链接https://atcoder.jp/contests/abc200A-Century简单的abs(n-1)/100+1即可B-200thABC-200按题意写代码点击查看代码voidsolve(){intn,k;cin>>n>>k;for(inti=1;i<=k;i++){if(n%200==0)n/=200;elsen=n*1000+200;}......
  • 泛型编程(Generic Programming)
    泛型编程(GenericProgramming)虚函数->含有虚函数的类就是抽象类编译(compile)链接(link)转换函数(Conversionfunction)例如将小数转成分数,就是一个转换函数#pragmaonce#ifndef__FRACTION__#define__FRACTION__​classFraction{public://分母不为0,所......
  • C语言实现半定规划(Semidefinite Programming, SDP)算法
    目录前言A.建议B.简介一代码实现A.半定规划的基本概念B.使用C语言进行半定规划建模二时空复杂度A.时间复杂度B.空间复杂度C.实际考虑三优缺点A.优点B.缺点C.总结四现实中的应用前言A.建议1.学习算法最重要的是理解算法的每一步,而不是记住算法。2.......
  • The 19th Zhejiang Provincial Collegiate Programming Contest
    目录写在前面CBALMGIFJ写在最后写在前面比赛地址:https://codeforces.com/gym/103687。以下按照个人向难度排序JustaWay闪击珞珈之初次合作。理应能7题,但是赛时开局罚烂中期烂了两题导致后面的没法写被迫五题下班妈的唉牢鱼想你了C纯签到,建议评级:200///*By:Luckybl......
  • UNIQUE VISION Programming Contest 2024 Spring(AtCoder Beginner Contest 346)
    C我们用\(1\simK\)的和减去出现在\(1\simK\)中的数的和。intn,k,a[N],res;map<int,int>vis;signedmain(){ cin>>n>>k; _for(i,1,n)cin>>a[i]; res=k*(1+k)/2; _for(i,1,n)if(a[i]>=1&&a[i]<=......
  • Programming Abstractions in C阅读笔记:p338-p346
    《ProgrammingAbstractionsinC》学习第80天,p338-p346,总计9页。一、技术总结栈的实现包括入栈、出栈、判断栈是否为满,判断栈是否为空等。作者结合RPN计算器来实现,稍显无聊。/**File:rpncalc.c*---------------*Thisprogramsimulatesanelectroniccalculatorth......
  • 『The Go Programming Language』二、程序结构
    2.1名称名称开头通常为字母或下划线且区分大小写。存在25个关键字只能用于合法处不能用作名称:breakdefaultfuncinterfaceselectcasedefergomapstructchanelsegotopackageswitchconstfallthroughifrangetypecontinueforimportreturnvar此外还存在预声明的常量、类型和函......
  • The 14th Jilin Provincial Collegiate Programming Contest
    The14thJilinProvincialCollegiateProgrammingContest-Codeforces队友太猛了,我整场就只写了D,其他题给队友开完了,预计补一下M,FProblemD.Trie(AC自动机+树状数组)大概就是给定一颗Trie树操作一是给Trie树的fail树上一个集合中的点的所有子节点打上一个......
  • Programming Abstractions in C阅读笔记:p327-p330
    《ProgrammingAbstractionsinC》学习第78天,p327-p330,总计4页。一、技术总结1.ADT(抽象数据类型)p328,Atypedefinedintermofitsbehaviorratherthanitsrepresnetationiscalledanabstractdatatype(如果一种数据类型使用它们的行为而不是表示来定义,那么这样的......