time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
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
Copy
7 5
1 4
4 5
5 6
6 7
3 5
output
Copy
7
input
Copy
4 3
1 1
2 2
3 4
output
Copy
2
input
Copy
4 4
1 1
2 2
2 3
3 4
output
Copy
题意就是找q-2个区间使得尽量覆盖n区间的长度。
别人的代码加自己的注释:
先把所有区间内都加上1,然后枚举两个区间,把这两个区间内减1,统计0的个数
反过来求,找两个区间,假设去掉这两个区间,求剩下的区间能覆盖的长度。维护最大值即可。
问题一:那么如何求 “剩下的区间能覆盖的长度” ?
解决问题一:
先假设求一个区间:假设去掉这一个区间,剩下的q-1个区间能覆盖的最大区间。
先给一个前提:把每个画匠能画的区间全部加上一:
7 5
1 4
4 5
5 6
6 7
3 5
那么预处理数组a为1 1 2 3 3 2 1
枚举1 4,去掉1 4则将a数组内1到4全部减一:0 0 1 2 3 2 1,0的个数就是不能覆盖的区间,剩下的q-1个区间能覆盖的区间为7-2=5;
统计0的个数直接用sum[i][1]
保存a数组中的1的前缀和就可以了。1就是只被一个区间覆盖
用sum[r][1]-sum[l-1][0]可O(1)求0的个数
这里的sum【1】应为1 2 2 2 2 2 3
问题二:如何求去掉两个区间后,剩下的区间能覆盖的长度?
解决问题二:
如果两个区间没有交叉,那么就当作两个去掉一个区间处理,
就是解决问题一提到的方法。
如果两个区间有交叉。将交叉的地方特殊处理,
不交叉的地方当作一个区间处理。
将交叉的地方特殊处理:
保存a数组中的2的前缀和就可以了。
然后将sum[r][2]-sum[l-1][2],就是0的个数(不能被覆盖的个数)。
因为如果a数组中为3,那就是三个区间交叉,无论去掉哪两个,这个3区间还是能被覆盖。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=5005;
int l[maxn],r[maxn],a[maxn],n,ans,res;
int sum[maxn][4];
int main()
{
int q;
scanf("%d%d",&n,&q);
for(int i=1;i<=q;i++)
{
scanf("%d%d",&l[i],&r[i]);
a[l[i]]++,a[r[i]+1]--;//先将左区间加一,右区间减一,
//然后求前缀和即实现了 把每个画匠能画的区间全部加上一
}
for(int i=1;i<=n;i++)
{
a[i]+=a[i-1];//求前缀和
if(a[i])res++;//res是能被覆盖总区间
//维护a中1的前缀和 和2的前缀和
for(int j=0;j<3;j++)
sum[i][j]=sum[i-1][j];
if(a[i]==1)sum[i][1]++;
if(a[i]==2)sum[i][2]++;
}
for(int i=1;i<q;i++)//枚举两个区间 求两个区间不能被覆盖的最小值t
for(int j=i+1;j<=q;j++)
{
int ql=max(l[i],l[j]);
int qr=min(r[i],r[j]);
if(ql>qr)//无重叠
{
int t=sum[r[i]][1]-sum[l[i]-1][1];
t+=sum[r[j]][1]-sum[l[j]-1][1];
ans=max(ans,res-t);
}
else//有重叠
{
int t=sum[qr][2]-sum[ql-1][2];//重叠部分
int ll=min(l[i],l[j]);
int rr=max(r[i],r[j]);
t+=sum[ql][1]-sum[ll-1][1];//非重叠部分
t+=sum[rr][1]-sum[qr][1];
ans=max(ans,res-t);
}
}
cout<<ans;
}