题目链接:http://codeforces.com/problemset/problem/1132/C
题目大意:就是有个n长的栅栏,然后每个油漆工可以染的区域不同
给你q让你选出q-2个人使得被染色的栅栏最多
思路:Q的范围允许O(n*n)复杂度,先预处理每个格子被覆盖非0次,被覆盖1次,被覆盖2次的情况,再暴力枚举去掉哪两条就ok,假如去掉X和Y两条,那么覆盖数量减少为X和Y交集部分的覆盖2次的格子数加上X和Y部分并集的覆盖1次的格子数,这些通过前缀和方便求出来。
对于并集的求法,并不需要求并集。因为他们的交集覆盖了至少为2次。所以把这两个直接减去就可以了。
#include<bits/stdc++.h>
#define LL long long
using namespace std;
int sum[5005], f[5005], one[5005], tow[5005];
int L[5005], R[5005];
int fun(int i, int j){
if(L[i]>L[j]){
swap(i, j);
}
if(L[j]>R[i]){
return 0;
}
int t=min(R[i], R[j]);
return max(0, tow[t]-tow[L[j]-1]);
}
int main()
{
int n, q;
scanf("%d%d", &n, &q);
for(int i=1; i<=q; i++){
scanf("%d%d", &L[i], &R[i]);
sum[L[i]]++, sum[R[i]+1]--;
}
for(int i=1; i<=n; i++){
sum[i]+=sum[i-1];
f[i]=f[i-1];
one[i]=one[i-1];
tow[i]=tow[i-1];
if(sum[i]){
f[i]+=1;
}
if(sum[i]==1){
one[i]++;
}
if(sum[i]==2){
tow[i]++;
}
}
LL ans=0;
for(int i=1; i<=q; i++){
for(int j=i+1; j<=q; j++){
LL s=f[n];
s-=fun(i, j);//交集
s-=(one[R[i]]-one[L[i]-1]);
s-=(one[R[j]]-one[L[j]-1]);
ans=max(s, ans);
}
}
printf("%lld\n", ans);
return 0;
}