Solution
看了一圈题解都是优先队列, 这里给个不正经的做法
观察到人数只会在 到
我们考虑会不会出现一个峰值使得结果最大
即这个结果是不是满足凹凸函数的定义
我们考虑三分人数大小, 这样可以取得一个局部极值
然后在这个局部极值的附近找是否有最优的
问题在于三分出人数后如何去check贡献
因为我们已经知道了人数
于是那些 比当前人数小的都不能选
剩下的那些只需要按 排序一个一个选即可
虽然我觉得我的做法很假
但是就是过了啊hhhh
update
被 了
老老实实写优先队列吧
首先按 排序, 然后以
值建立一个小根堆(优先队列)
然后对于当前的 先进入队列(注意这一步很重要, 判断完再进队是错的)
为什么是错的? 因为这个点我们可能根本就不需要取, 所以不能弹出多余的元素再入队, 要直接入队
然后此时判断 跟队列大小, 弹出队里最小的元素
在模拟的过程中不断更新答案即可
正解Code
/*
autor: Kurisu
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const long long inf = 1e18;
const int N = 1e6 + 5;
const double eps = 1e-10;
const ll mod = 23333333333333333;
struct node {
ll v, s;
bool operator < (const node &s) const {
return v < s.v;
}
}a[N];
int main() {
int n;
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> a[i].v >> a[i].s;
}
sort(a + 1, a + 1 + n, [](const node &x, const node &y) {return x.s > y.s;});
priority_queue<ll, vector<ll>, greater<ll> > q;
ll ans = 0, res = 0;
for(int i = 1; i <= n; i++) {
q.push(a[i].v);
res += a[i].v;
while(!q.empty() && q.size() > a[i].s) res -= q.top(), q.pop();
ans = max(ans, res);
}
cout << ans << '\n';
return 0;
} 三分水过Code
/*
autor: Kurisu
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const long long inf = 1e18;
const int N = 1e6 + 5;
const double eps = 1e-10;
const ll mod = 23333333333333333;
struct node {
ll l, r;
bool operator < (const node &s) const {
return l > s.l;
}
}a[N];
int n;
ll val(int x) {
int last = x;
ll res = 0;
for(int i = 1; i <= n; i++) {
if(x <= a[i].r) {
res += a[i].l;
last--;
}
if(!last) break;
}
return res;
}
int main() {
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i].l >> a[i].r;
sort(a + 1, a + 1 + n);
int left = 1, right = n; // 三分人数
while(right - left > 5) {
int mid = left + right >> 1;
int midmid = mid + right >> 1;
if(val(mid) >= val(midmid)) {
right = midmid - 1;
}
else left = mid + 1;
}
ll ans = 0;
for(int i = max(1, left - 100); i <= min(n, left + 100); i++) ans = max(ans, val(i));
cout << ans << "\n";
return 0;
} 
京公网安备 11010502036488号