显然有贪心:每一类都按照 x 从大到小排序。
思路是枚举选 i 个 0 类物品,然后二分一个 k,使得选 k 个 2 类物品就可以把剩下还能选的 m−i−k 个 1 类物品全部撬开。
整个过程都用到了前缀和的优化。
时间复杂度 O(mlogn),但是 WA 了 9 个点,边界啥的我都注意到了,烦请大佬帮忙调调!!!!
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 10;
int n, m, la, lb, lc, a[N], b[N], c[N], sa[N], sb[N], sc[N];
bool cmp(int a, int b){
return a > b;
}
bool check(int x, int len){
return sc[x] >= min(lb, len - x);
}
main(){
cin >> n >> m;
for(int i=1,t,x;i<=n;i++){
cin >> t >> x;
if(t == 0)
a[++la] = x;
if(t == 1)
b[++lb] = x;
if(t == 2)
c[++lc] = x;
}
sort(a + 1, a + 1 + la, cmp);
sort(b + 1, b + 1 + lb, cmp);
sort(c + 1, c + 1 + lc, cmp);
for(int i=1;i<=la;i++)
sa[i] = sa[i - 1] + a[i];
for(int i=1;i<=lb;i++)
sb[i] = sb[i - 1] + b[i];
for(int i=1;i<=lc;i++)
sc[i] = sc[i - 1] + c[i];
int ans = 0;
for(int i=0;i<=min(la,m);i++){
int l = 0, r = min(lc, m - i), cnt = -1;
while(l <= r){
int mid = (l + r) >> 1;
if(check(mid, m - i))
cnt = mid, r = mid - 1;
else
l = mid + 1;
}
if(cnt == -1)
continue;
// cout << i << ' ' << ans +
int pos = min(lb, m - i - cnt);
ans = max(ans, sa[i] + sb[max(0ll, pos)]);
}
printf("%lld\n", ans);
return 0;
}