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

来源:互联网 发布:多功能qq视频录像软件 编辑:程序博客网 时间:2024/05/18 01:21

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 31 32 65 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;}