题目链接:点击打开链接
思路:先将区间处理成不相交区间,补签肯定是要选择相邻的空隙,这样才能使分散的天数连起来从而最大化签到天数,然后再考虑,具体要如何选择呢?DP?看不出状态转移;贪心?局部最优解规则不明显,优先选择签到天数多的或者优先选择空隙大的去补签都不正确;这样看,此题该采用枚举之类的做法?难道暴力枚举被选择空隙的范围?肯定不可以,这样复杂度达到了O(n ^ 2),会超时;其实这里枚举空隙范围就是枚举的区间,采用高效枚举区间的算法尺取法,正好解决此问题,而且签到的规则正好也符合尺取法根据区间特征有方向的枚举的特点。
// 小小粉丝度度熊.cpp 运行/限制:202ms/1000ms
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
struct node {//区间
int le, rig;
bool operator<(const node a)const {
return this->le < a.le;
}
}a[100005];
int hole[100005];//空隙大小
int main(){
int n, m;
while (scanf("%d%d", &n, &m) != EOF) {
for (int i = 0; i < n; i++) {
scanf("%d%d", &a[i].le, &a[i].rig);
}
sort(a, a + n);
int top = 0;
for (int i = 1; i < n; i++) {//将所有区间处理成不相交区间
if (a[i].rig <= a[top].rig) continue;
if (a[i].le <= a[top].rig + 1) {
a[top].rig = a[i].rig;
continue;
}
top++;
a[top] = a[i];
}
//取空隙
for (int i = 0; i < top; i++) {
hole[i] = a[i + 1].le - a[i].rig - 1;
}
//对空隙选择采用尺取法 (0,top - 1)
int left = 0, right = 0;
int re = m, te = m;
while (right <= top) {//注意此处范围
while (right < top && te >= hole[right]) {
te -= hole[right];
right++;
}
re = max(re, a[right].rig - a[left].le + 1 + te);
if (left != right) {
te += hole[left];
}
left++;
if (left > right) right++;
}
printf("%d\n", re);
}
return 0;
}