题意

个任务,每个任务有个完成时间 和截止时间 。问最多能完成多少任务。

分析

这道题还是挺难的QAQ。
首先看到这题,我们可以先将问题转化一下:
假设最终做的任务序列为 ,那么对任意 需满足 ,也就是:




...

我们现在要让这个序列尽量长。
然后有一个基础的想法:对于每个 ,我们要求满足上式的最长序列。然后对于同一个长度 ,肯定在合法的条件下,让 越小越好,因为这样能多出更多时间。
然后考虑暴力,我们可以对维护一个 ,每个 储存合法的长度和最小的前缀和。每次枚举到一个 ,更新所有合法的长度及其对应的最小前缀和(从 更新到 )。这样复杂度是 的。
要继续往下做,我们要发现: 的序列仅仅差了一个数,这个数就是
于是,我们其实不用存 ,我们只用记录当前最长序列的前缀和 和最大值 即可。
如果 ,那么可以更新最长序列。
如果 ,那么如果 ,把 换成 只会使答案更优。(相当于是后悔之前的选择)
这种思想和求最长上升子序列的 解法的思想有相似之处。
维护最大值可以用优先队列维护。最终复杂度是 的。

代码如下

#include <bits/stdc++.h>
#define N 150005
using namespace std;
typedef long long LL;
LL z = 1;
LL read(){
    LL x, f = 1;
    char ch;
    while(ch = getchar(), ch < '0' || ch > '9') if(ch == '-') f = -1;
    x = ch - '0';
    while(ch = getchar(), ch >= '0' && ch <= '9') x = x * 10 + ch - 48;
    return x * f;
}
priority_queue<LL> q;
struct node{
    LL t1, t2;
    bool operator < (const node & A) const{
        return t2 < A.t2;
    }
}d[N];
int main(){
    int i, j, n, m, ans = 0;
    LL t = 0, t1, t2;
    n = read();
    for(i = 1; i <= n; i++) d[i].t1 = read(), d[i].t2 = read();
    sort(d + 1, d + i);
    for(i = 1; i <= n; i++){
        t1 = d[i].t1, t2 = d[i].t2;
        if(t + t1 <= t2) t += t1, q.push(t1), ans++;
        else if(q.top() > t1) t += t1 - q.top(), q.pop(), q.push(t1);
    }
    printf("%d", ans);
    return 0;
}