题目大意
有 n n n头奶牛,编号为 1 1 1到 n n n。有 m m m个区间 [ l , r ] [l,r] [l,r],每个区间 [ l , r ] [l,r] [l,r]都有且只有一头有斑点的奶牛。求这些牛中最多有多少头有斑点的奶牛。如果出现矛盾,则输出 − 1 -1 −1。
1 ≤ n ≤ 2 × 1 0 5 , 1 ≤ m ≤ 1 0 5 1\leq n\leq 2\times 10^5,1\leq m\leq 10^5 1≤n≤2×105,1≤m≤105
题解
设 f i f_i fi表示第 i i i头奶牛是有斑点的奶牛时前 i i i头奶牛中最多有多少头有斑点的奶牛,那么转移式为
f i = max ( f j ) + 1 f_i=\max(f_j)+1 fi=max(fj)+1
其中 j < i j<i j<i且 j j j满足一定条件。
对于 j j j转移到 i i i,即 j j j和 i i i都是有斑点的奶牛, [ j + 1 , i − 1 ] [j+1,i-1] [j+1,i−1]上都是没有斑点的奶牛。
依题意,每个区间 [ l , r ] [l,r] [l,r]都有且只有一头有斑点的奶牛,我们可以把这个条件转化为每个区间最多有一条奶牛,最少有一条奶牛。
最多有一头奶牛
如果 i i i和 j j j在同一个区间 [ l , r ] [l,r] [l,r]中,则这个区间会有两头奶牛。那么,对于任意包含 i i i的区间 [ l , r ] [l,r] [l,r], j j j需要满足小于 l l l。
设 m n i mn_i mni表示包含 i i i的区间中最小的 l l l,则
m n i = min ( 右端点为 i 的区间的最小的 l , m n i + 1 ) mn_i=\min(右端点为i的区间的最小的l,mn_{i+1}) mni=min(右端点为i的区间的最小的l,mni+1)
即在右端点等于 i i i和右端点大于 i i i的所有区间中求出最小的左端点。
最少有一头奶牛
如果区间 [ l , r ] [l,r] [l,r]在 i i i和 j j j之间,则这个区间没有奶牛。那么,对于任意 r < i r<i r<i的区间, j j j需要满足大于等于 l l l。
设 m x i mx_i mxi表示右端点小于 i i i的区间中最大的 l l l,则
m x i = max ( 右端点为 i − 1 的区间的最大的 l , m x i − 1 ) mx_i=\max(右端点为i-1的区间的最大的l,mx_{i-1}) mxi=max(右端点为i−1的区间的最大的l,mxi−1)
即在右端点等于 i − 1 i-1 i−1或右端点小于 i − 1 i-1 i−1的所有区间中求出最大的左端点。
转移式
那么,我们就能得到 f i f_i fi的转移式:
f i = f j + 1 ( m x i ≤ j < m n j ) f_i=f_j+1\qquad(mx_i\leq j< mn_j) fi=fj+1(mxi≤j<mnj)
我们可以在最后设一个点 n + 1 n+1 n+1来统计答案。
因为 m x j mx_j mxj和 m n j mn_j mnj都单调不下降,所以我们可以用单调队列来优化。
时间复杂度为 O ( n ) O(n) O(n)。
code
#include<bits/stdc++.h>
using namespace std;
int n,m,hd=1,tl=0,mn[200005],mx[200005],q[200005],f[200005];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n+1;i++) mn[i]=i;
for(int i=1,l,r;i<=m;i++){
scanf("%d%d",&l,&r);
mn[r]=min(mn[r],l);
mx[r+1]=max(mx[r+1],l);
}
for(int i=n;i>=1;i--){
mn[i]=min(mn[i],mn[i+1]);
}
for(int i=1;i<=n+1;i++){
mx[i]=max(mx[i],mx[i-1]);
}
q[++tl]=0;
for(int i=1,j=1;i<=n+1;i++){
for(;j<mn[i];j++){
if(f[j]==-1) continue;
while(hd<=tl&&f[q[tl]]<f[j]) --tl;
q[++tl]=j;
}
while(hd<=tl&&q[hd]<mx[i]) ++hd;
if(hd<=tl) f[i]=f[q[hd]]+(i!=n+1);
else f[i]=-1;
}
printf("%d",f[n+1]);
return 0;
}