本来以为这道题是考不相交区间, 结果还专门复习了一遍前面写的, 然后发现这道题的区间是不是
固定的, 是在一个范围内“滑动的”, 只要右端点不超过截止时间就ok。
然后我就先考虑有包含关系的时候怎么选, 然后发现当两个区间只能放一个的时候时间更短而截
至时间更长的时候,显然更优。然后我就试着每个区间放的时候后后面的比较, 如果两个区间只能放一个, 而且
下个区间更优, 那么当前的就不选。然后排除掉这些区间之后, 能选的就选。
交上去WA。然后我发现中间的区间排除了,但是前面和后面的区间可能会矛盾, 也要排除
我就想不到什么方法来实现了。
后来参考了https://blog.csdn.net/u013520118/article/details/48008741
发现我其实已经想了80%了, 但是最后20%怎么实现没有想到。这里用到优先队列来实现,
优先队列中储存了之前已经放过的所有区间, 然后能放就放, 不能放就往前和已经放了
的区间比较, 更优的话就放当前的区间, 取消之前的区间。
一直怎么做就可以了。这么做为什么可以呢, 因为这样就可以考虑到所有区间之间的“包含”关系
让所有区间里面最不优的都舍去了, 所以最后答案就是最优的。
然后我就继续想, 为什么紫书前面讲区间的时候都是相邻的比较来舍去, 而这个要考虑前面所有
放过的区间。
然后我发现, 紫书上选区间的时候是前一个比后一个更优的。
然而这道题,放的时候相邻的两个区间不一定前一个优于后一个, 因为就算后一个更差, 只要
不超过截止时间, 就可以放。
那么这就导致了, 这道题排在后面的区间显然不一定优于前面的区间(优指时间更短且截止时间更后),
所以不具有连续性, 也就是说要考虑当前区间和前面所有区间里面“最差”的那一个, 也就是需要时间最长
的一个来取最优, 所以这才证明了贪心的正确性。
我觉得自己讲得非常抽象, 看不懂也可以简单的理解为能放就放, 不能放就拿一个最差的来换, 这样结果
肯定是最优的。
#include<cstdio>
#include<queue>
#include<algorithm>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std;const int MAXN = 812345;
struct node
{int d, q;bool operator < (const node& x) const{return q < x.q;}
}a[MAXN];bool cmp(node a, node b)
{return a.d < b.d;
}int main()
{int T, n;scanf("%d", &T);while(T--){priority_queue<int> Q;scanf("%d", &n);REP(i, 0, n) scanf("%d%d", &a[i].q, &a[i].d);sort(a, a + n, cmp);int start = 0;REP(i, 0, n){if(start + a[i].q <= a[i].d) start += a[i].q, Q.push(a[i].q);else if(Q.size() && a[i].q < Q.top()){start += a[i].q - Q.top();Q.pop(); Q.push(a[i].q);}}printf("%d\n", Q.size());if(T) puts("");}return 0;
}