前言
每次期末后的复建运动都格外痛苦(
正文
题意是说,给定\(n\)本书,如果书都有属性\(a,b,t\)。如果\(a=1\),则说明Alice喜欢读这本书,\(0\)则不喜欢;如果\(b=1\),则说明Bob喜欢读这本书,\(0\)则不喜欢。\(t\)是每本书的代价。从中选出若干本书,这些书中Alice和Bob喜欢读的都不少于\(k\)本。问如何选择,才能使代价总和最小。
思路是贪心。记Alice和Bob都喜欢的书为11类,只有Alice喜欢的为10类,只有Bob喜欢的为01类。容易注意到,选择Alice和Bob都喜欢读的书性价比要更高一些。所以,我们首先对三种属性分别排序,如果当前取了\(i\)本11类的书,那么,对于Alice,我们要为她取10类和01类共\(k-i\)本书;Bob也是同理。如果发现10类或01类的书的数目小于\(k-i\),则说明在取\(i\)本11类书的情况下,没有可行的方案。
代码如下:
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <limits>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <vector>
#define mst(a, b) memset((a), (b), sizeof(a))
#define debug printf("debug\n")
#define INF 0x3f3f3f3f
#define lson lef, mid, rt << 1
#define rson mid + 1, rig, rt << 1 | 1
const int maxn = 2e5 + 5;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
struct node {
ll t;
int a;
int b;
bool operator<(const node& nn) const
{
return t < nn.t;
}
};
node allone[maxn];
node A[maxn];
node B[maxn];
ll sum1[maxn];
ll sum2[maxn];
ll sum3[maxn];
unordered_map<int, bool> mp;
int main()
{
mp.clear();
int n, k;
scanf("%d %d", &n, &k);
int idx1, idx2, idx3;
idx1 = idx2 = idx3 = 1;
ll t_;
int a_, b_;
for (int i = 1; i <= n; i++) {
scanf("%lld %d %d", &t_, &a_, &b_);
if (a_ && b_)
allone[idx1++] = { t_, a_, b_ };
if (a_ && !b_)
A[idx2++] = { t_, a_, b_ };
if (!a_ && b_)
B[idx3++] = { t_, a_, b_ };
}
sort(allone + 1, allone + idx1);
sort(A + 1, A + idx2);
sort(B + 1, B + idx3);
for (int i = 1; i <= n; i++) {
sum1[i] = sum1[i - 1] + allone[i].t;
sum2[i] = sum2[i - 1] + A[i].t;
sum3[i] = sum3[i - 1] + B[i].t;
}
ll inf = numeric_limits<ll>::max();
ll ans = inf;
for (int i = 0; i <= min(k, idx1 - 1); i++) {
int tmp = k - i;
if (idx2 - 1 >= tmp && idx3 - 1 >= tmp) {
ans = min(ans, sum1[i] + sum2[k - i] + sum3[k - i]);
}
}
if (ans == inf) {
puts("-1");
} else {
printf("%lld\n", ans);
}
return 0;
}