2017百度之星初赛(B) 1006 小小粉丝度度熊(尺取法)

题目链接:点击打开链接

思路:先将区间处理成不相交区间,补签肯定是要选择相邻的空隙,这样才能使分散的天数连起来从而最大化签到天数,然后再考虑,具体要如何选择呢?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;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值