题目链接:https://codeforces.com/contest/1132/problem/C
题意:
栅栏有 $n$ 个节,有 $q$ 个人可以雇佣来涂栅栏,第 $i$ 个人可以涂第 $l_i$ 节到第 $r_i$ 节。
但是现在预算紧张,所以只能雇佣 $q-2$ 个人,你想确认雇佣哪 $q-2$ 个人使得涂色栅栏的节数最大。
题解:
首先看到 $n$ 的范围,就可以想到大概可以枚举第一个不雇佣的人再枚举第二个不雇佣的人,时间复杂度在 $O(n^2)$ 左右。
先假定第一个不雇佣的人是第 $x$ 个人,然后剩下的 $q-1$ 个人,他们的涂栅栏情况用数组 $c$ 记录,$c_i$ 表示第 $i$ 节有多少人涂。
然后我们用另一个数组 $d$ 对应到数组 $c$,若 $c_i = 1$,则 $d_i = 1$;否则 $d_i = 0$。这样一来就能对每个人,用前缀和优化 $O(1)$ 地求出仅他能涂的栅栏节数。
这样,我们用数组 $c$ 所有 $c_i > 0$ 的 $i$ 的数目减去仅这个人能涂抹的节数,就知道最终能涂多少节。
AC代码:
#include<bits/stdc++.h> using namespace std; typedef pair<int,int> P; #define mk(x,y) make_pair(x,y) #define fi first #define se second const int maxn=5e3+10; int n,q; P p[maxn]; int cnt[maxn],sum[maxn]; int main() { cin>>n>>q; memset(cnt,0,sizeof(cnt)); for(int i=1;i<=q;i++) { cin>>p[i].fi>>p[i].se; for(int k=p[i].fi;k<=p[i].se;k++) cnt[k]++; } int ans=0; for(int x=1;x<=q;x++) { for(int k=p[x].fi;k<=p[x].se;k++) cnt[k]--; int tot=0; for(int k=1;k<=n;k++) { tot+=(cnt[k]>0); if(cnt[k]==1) sum[k]=1; else sum[k]=0; sum[k]+=sum[k-1]; } int Max=0; for(int y=1;y<=q;y++) { if(x==y) continue; Max=max(Max,tot-(sum[p[y].se]-sum[p[y].fi-1])); } ans=max(ans,Max); for(int k=p[x].fi;k<=p[x].se;k++) cnt[k]++; } cout<<ans<<endl; }