题意
有 个任务,每个任务有个完成时间
和截止时间
。问最多能完成多少任务。
分析
这道题还是挺难的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;
}
京公网安备 11010502036488号