codeforces 332C Students' Revenge 贪心

本文介绍了一种解决特定问题的工作选择策略算法,该算法通过两轮筛选来最大化主席的白头发数量同时尽量减少不满意的工作数量。首先,根据工作属性进行排序并移除部分选项;其次,再次筛选剩余工作以满足条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简略题意:有n项工作,每项工作有两个属性ab,代表如果主席接受了这份工作,就要长a根白头发,不接受董事会就要有b的不满意度。我们需要从n项工作里挑出p项工作使得主席的白头发尽可能多,多种方案选董事会最不满意的那个方案。而主席从p份工作里挑k个工作,首先使得董事会满意,多种方案选取自己白头发最少的方案。

先明确主动权在我们手里,对于主席而言理想化的状况就是选了b最小的pk份工作,然后不做,并且这pk份工作的a值还很大。所以我们尽可能让这pk份工作不会被选上。
先按b升序,a降序排序,去除掉前pk份工作。

现在我们手上有n(pk)份工作,我们需要从里面挑出a最大的k份工作给主席做,并且为了保证这几份工作一定会被做,我们还要确保这几份工作里面b的最小值也要大于等于没被做的工作的最大值。

然后在剩下的nk份工作中,找出满足上述加粗部分条件的b尽可能大的若干份工作。需要注意的是,假如被做的工作中有着最小b值的(ai,bi),和我们当前准备不做的工作(aj,bj)满足bi==bjai<aj,那么我们就不能选这份工作,因为如果选上了这份工作,他们的关系就会交换,那么就不能保证a是最大的了。

#define others
#ifdef poj
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#endif // poj
#ifdef others
#include <bits/stdc++.h>
#endif // others
//#define file
#define all(x) x.begin(), x.end()
using namespace std;
const double pi = acos(-1.0);

typedef long long LL;
typedef unsigned long long ULL;
void umax(int &a, int b) {
    a = max(a, b);
}
void umin(int &a, int b) {
    a = min(a, b);
}

void file() {
    freopen("a.in", "r", stdin);
//    freopen("1.txt", "w", stdout);
}

namespace Solver {
    struct A {
        int a, b, id, tag;
    } V[110000];
    bool cmp1(A x, A y) {
        if(x.b != y.b) return x.b < y.b;
        return x.a > y.a;
    }
    bool cmp2(A x, A y) {
        if(x.a != y.a) return x.a > y.a;
        return x.b > y.b;
    }
    bool cmp3(A x, A y) {
        if(x.b != y.b) return x.b > y.b;
        return x.a > y.a;
    }
    int n, p, k;
    void solve() {
        scanf("%d%d%d", &n, &p, &k);
        for(int i = 1; i <= n; i++) {
            int a, b;
            scanf("%d%d", &a, &b);
            V[i].a = a, V[i].b = b, V[i].id = i, V[i].tag = 0;
        }
        sort(V + 1, V + 1 + n, cmp1);
        sort(V + 1 + p - k, V + 1 + n, cmp2);
        int mina = 0x3f3f3f3f, minb = 0x3f3f3f3f;
        vector<int> res;
        for(int i = p - k + 1; i <= p; i++) {
            V[i].tag = 1;
            res.push_back(V[i].id);
            if(minb > V[i].b) {
                minb = V[i].b;
                mina = V[i].a;
            }
        }
        sort(V + 1, V + 1 + n , cmp3);
        for(int i = 1, cnt = 0; i <= n && cnt < p-k; i++) {
            A x = V[i];
            if(x.tag == 1) continue;
            if(minb == V[i].b && V[i].a < mina) continue;
            if(minb >= V[i].b) cnt++, res.push_back(x.id);
        }
        for(int i = 0; i < res.size(); i++) printf("%d ", res[i]);
    }
};

int main() {
//    file();
    Solver::solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值