Codeforces 1132 C 反向思维+枚举

32 篇文章 0 订阅

http://codeforces.com/problemset/problem/1132/C

You have a long fence which consists of nn sections. Unfortunately, it is not painted, so you decided to hire qq painters to paint it. ii-th painter will paint all sections xx such that li≤x≤rili≤x≤ri.

Unfortunately, you are on a tight budget, so you may hire only q−2q−2 painters. Obviously, only painters you hire will do their work.

You want to maximize the number of painted sections if you choose q−2q−2 painters optimally. A section is considered painted if at least one painter paints it.

Input

The first line contains two integers nn and qq (3≤n,q≤50003≤n,q≤5000) — the number of sections and the number of painters availible for hire, respectively.

Then qq lines follow, each describing one of the painters: ii-th line contains two integers lili and riri (1≤li≤ri≤n1≤li≤ri≤n).

Output

Print one integer — maximum number of painted sections if you hire q−2q−2 painters.

Examples

Input

7 5
1 4
4 5
5 6
6 7
3 5

Output

7

Input

4 3
1 1
2 2
3 4

Output

2

Input

4 4
1 1
2 2
2 3
3 4

Output

3

题目大意:现在有[1,n]n节栅栏需要填充颜色,给出q个工人可以涂抹的左右区间,你可以从中雇佣q-2个人,求涂抹区间的最大值。

思路:这题我一直在正着想,一直没有好的思路,看了别人的想法豁然开朗。既然要雇佣q-2个人,那么反着思考就是有2个人不雇佣,那么我们可以枚举这各两个人,时间复杂度O(n^2),是可行的。我们用cnt[i]表示可以涂抹第i节栅栏的人数,用vis[i]表示[1,i]区间内只能被1个人涂抹的栅栏总数,那么在外层循环,枚举i,我们先修改cnt数组的值,(要把第i个的贡献抹去)然后遍历区间[1,n]统计可以涂抹的栅栏总数并计算出vis数组,内层循环枚举j,此时若一节栅栏可以被多人涂抹,那么抹去j的贡献是没有影响的;若一节栅栏只能被j涂抹,那么就要删去这节栅栏,而通过vis数组我们可以知道,只能被第j个人涂抹的栅栏数就是:vis[r[j]]-vis[l[j]-1],用sum减去这个值就是不雇佣第i个人和第j个人所能涂抹的栅栏节数,那么用一个变量MAX维护即可。

#include<iostream>
#include<cstring>
#include<cstdio>
typedef long long ll;
using namespace std;

int n,q,MAX;
int vis[5005];//记录[1,i]区间内只能被一人涂抹的栅栏的节数
int cnt[5005];//记录可以涂抹第i节栅栏的人数
int l[5005];//记录第i个人可以涂抹的栅栏的左端点
int r[5005];//记录第i个人可以涂抹的栅栏的右端点

int main()
{
	scanf("%d %d",&n,&q);
	for(int i=1;i<=q;i++)
	{
		scanf("%d %d",&l[i],&r[i]);
		for(int j=l[i];j<=r[i];j++)
			++cnt[j];
	}
	for(int i=1;i<=q;i++)//枚举 不雇佣第i个人和第j个人
	{
		for(int j=l[i];j<=r[i];j++)
			--cnt[j];//该人涂抹的区间的人数要减1
		int sum=0;
		for(int j=1;j<=n;j++)
		{
			if(cnt[j]==1)//只能一个人涂抹
				vis[j]=vis[j-1]+1;
			else//可以有多个人涂抹
				vis[j]=vis[j-1];
			if(cnt[j]>=1)//记录可以涂抹的栅栏总节数
				++sum;
		}
		for(int j=1;j<=q;j++)
		{
			if(i==j)//同一个人跳过
				continue;
			MAX=max(MAX,sum-(vis[r[j]]-vis[l[j]-1]));//记录最大值
		}
		for(int j=l[i];j<=r[i];j++)
			++cnt[j];//还原
	}
	printf("%d\n",MAX);
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值