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;
}