SER2016 DIV1(Paint)

本文介绍了一个关于最优分配的问题,即如何在多个画家间分配栅栏的涂漆任务以确保最少的未涂色区域。通过使用特定的数据结构和排序算法,文章提供了一种有效的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题 H: Paint

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

题目描述

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

题意:给你n块板子 K个画家,让这些人涂颜色,保证每个板子只能有一个画家涂色,这样最多可以有多少块没涂过,也就是求涂过了多少。

给你K个区间,求并集,保证没有交集的情况下,并集最大。
问了人,看了代码,自己思考了,才知道怎么写。
贴上代码 详细解释下,自己也多一翻记忆。
#include<stdio.h>
#include<iostream> 
#include <algorithm>
#include<string.h>
#include<vector>
#include<math.h>
#include<queue>
#include<set>
#define LL long long
#define INf 0x3f3f3f3f
using namespace std;
int dir[5][2]={0,1,0,-1,1,0,-1,0};
struct pp{
	int flag;//标记是左端点还是右端点 
	long long  x;//左端点 
	long long  t;//时间差值 
	long long  i;//第几个数字 
}p[400005];
long long  dp[400005];
bool cmp(pp a,pp b)
{
	if(a.x==b.x)//对于同一个点
		return a.flag<b.flag; //如果a 是 0  B 是 1 那就返回a
	return a.x<b.x;  //否则就按照时间从小打大处理
	//先按照左端点小的排列 有右端点小的话 先排左端点再排右端点 	
}
int main()
{
	long long x,xx,m,n;
	while(scanf("%lld%lld",&m,&n)!=EOF)
	{
		for(int i=1;i<=n;i++)
		{
			scanf("%lld%lld",&x,&xx); //2个对应的区间 1——1+n
			p[i].flag=0;  	//左端点 
			p[i].x=x;		//开始值 
			p[i].t=xx-x+1; //时间差值 
			p[i].i=i; 		//第区间
			
			p[i+n].flag=1;
			p[i+n].x=xx;
			p[i+n].t=xx-x+1;
			p[i+n].i=i;	//相对应的区间  便于查找 
		
		}
		sort(p+1,p+1+2*n,cmp);
		memset(dp,0,sizeof(dp));
		long long  maxx=0;
		for(int i=1;i<=2*n;i++)
		{
			if(p[i].flag==0)//如果左端点的话 还不会重复
				dp[p[i].i]=maxx+p[i].t;
			else //碰到了 右端点 
			{
				maxx=max(maxx,dp[p[i].i]); 
				//碰到了右端点,比较下当前最大和当前对应左端点涂了多少板子 
			} 
		}
		maxx=0;
		for(int i=1;i<=2*n;i++)
		{
			maxx=max(maxx,dp[i]);//求出来里面涂过板子最多的 
		}	
		printf("%lld\n",m-maxx);	
	}
	return 0;
} 

先排序,按照从小到大的顺序排列出来(具体看CMP),这样就可以扫描一边加上判断就足够了。
不太懂的话可以看下:http://blog.youkuaiyun.com/winter2121/article/details/77802808

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值