SER2016 DIV1 问题 H: Paint(区间问题贪心+dp优化)

http://exam.upc.edu.cn/problem.php?id=4213

问题 H: Paint

时间限制: 1 Sec  内存限制:128 MB
提交: 38  解决: 9
[提交][状态][讨论版]

题目描述

You are painting a picket fence with n slats, numbered from 1 to n. There are k painters willing to paint a specific portion of the fence. However, they don’t like each other, and each painter will only paint their given portion of the fence if no other painter overlaps their portion.
You want to select a subset of painters that do not conflict with each other, in order to minimize the number of unpainted slats. For example, suppose there are 8 slats, and 3 painters. One painter wants to paint slats 1->3, one wants to paint 2->6, and one wants to paint 5->8. By choosing the first and last painters, you can paint most of the slats, leaving only a single slat (slat 4) unpainted, with no overlap between painters.

输入

Each input will consist of a single test case. Note that your program may be run multiple times on different inputs. The first line of input contains two integers n (1≤n≤1018) and k (1≤k≤200,000), where n is the number of slats and k is the number of painters. Each of the next k lines contains two integers a and b (1≤a≤b≤n), indicating that this painter wants to paint all of the slats between a and b, inclusive.

输出

Output a single integer, which is the smallest number of slats that go unpainted with an optimal selection of painters.

样例输入

8 3
1 3
2 6
5 8

样例输出

1
【题意】:

可以理解为有k个区间,现在要选出一些区间,但不能有交集,使得这些区间的长度和最大(那么n减掉这个最大值就是没涂漆的最小长度)。

【解析】:
我的解法是把所有区间拆开成两个点。

每个点需要记录

1.左端点还是右端点

2.所在区间编号

3.此时刻

4.这个区间的长度

具体看代码中的结构体,结构体存的是点。


然后把所有点从小到大排序,开始扫描。(排序时注意,如果遇到重合的左右端点,先处理那个左端点)


定义一个dp数组来存状态。dp[i]表示第i个区间加上 当前点之前的区间,最大的长度和。

用一个变量maxtime来记录当前点之前,最大的长度和dp值

遇到右端点,就更新一下maxtime

遇到左端点,就把maxtime加上本区间,这个长度,赋值给本区间的那个dp


扫完一遍,就得到了dp数组,扫一遍dp数组,取最大值即可

【代码】:

#include <stdio.h>
#include <stdlib.h>  
#include <string.h>  
#include <algorithm> 
#define mset(a,i) memset(a,i,sizeof(a))
using namespace std;
typedef long long ll;
const int MAX=402020;
struct node{
	int flag;//左右 
	int i;//所在区间编号
	ll p;   //当前点 
	ll time; //长度
	node(int f=0,int ii=0,ll pp=0,ll t=0)//构造函数 
	{
		flag=f;i=ii;p=pp;time=t;
	}
}e[MAX];
ll n,m;
ll dp[MAX];
bool cmp(node a,node b)
{
	if(a.p==b.p)return a.flag<b.flag;//先处理左 
	return a.p<b.p;
}
int main()
{
	while(~scanf("%lld%lld",&n,&m))
	{
		for(int i=1;i<=m;i++)
		{
			ll x,y;
			scanf("%lld%lld",&x,&y);
			e[i]=node(0,i,x,   y-x+1);
			e[i+m]=node(1,i,y, y-x+1);
		}
		sort(e+1,e+1+2*m,cmp);
		mset(dp,0);//dp[i]第i个区间之前用的时间
		ll maxtime=0;
		for(int i=1;i<=2*m;i++)
		{
			if(e[i].flag==0)//左 
				dp[e[i].i]=maxtime+e[i].time;
			else  //右 
				maxtime=max(maxtime,dp[e[i].i]);
		}
		ll ans=0;
		for(int i=1;i<=m;i++)
			ans=max(ans,dp[i]);
		printf("%lld\n",n-ans);
	}
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪的期许

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值