Description
Input
Output
Sample Input
Input 1
10 3
0 3
3 7
7 0
Input 2
10 3
0 5
2 7
6 9
Sample Output
Output 1
3
Output 2
2
Data Constraint
Hint
分析:
对于每个区间,如果被包含则删掉包含他的区间。
如果不是有环,那么显然可以使用一维dp,即
f[i]=max(f[i−1],f[left]+1)
f
[
i
]
=
m
a
x
(
f
[
i
−
1
]
,
f
[
l
e
f
t
]
+
1
)
其中, left l e f t 代表以 i i 为右端点的区间的左端点,显然我们删掉一些区间后,只会剩下一个。
我们发现,对于任何一个环,跨过原点的区间只能有一个。所以我们把每个转移来的状态保留他一个最右边的边界 l[i] l [ i ] ,表示可以有最优解覆盖 l[i] l [ i ] 到 i i 。因为跨过原点只有一个区间,所以保留的右边界一定不会更优。然后枚举跨过 0 0 的区间,看能否是答案加。
要离散化,这个很恶心。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
const int maxn=5e5+7;
using namespace std;
int f[maxn],l[maxn],a[maxn],c[maxn*3],last[maxn*3];
int n,m,x,y,ans,num,cnt;
struct node{
int l,r;
}b[maxn];
map <int,int> h;
bool cmp(node x,node y)
{
if (x.r==y.r) return x.l>y.l;
return x.r<y.r;
}
int main()
{
freopen("circular.in","r",stdin);
freopen("circular.out","w",stdout);
scanf("%d%d",&m,&n);
for (int i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
x++; y++;
if (x>y) y+=m;
b[i]=(node){x,y};
}
sort(b+1,b+n+1,cmp);
for (int i=1;i<=n;i++)
{
if (b[i].r==b[i-1].r) continue;
c[++num]=b[i].l;
c[++num]=b[i].r;
if (b[i].r>m) c[++num]=b[i].r-m;
}
c[++num]=m;
c[++num]=2*m-1;
c[++num]=m-1;
sort(c+1,c+num+1);
cnt=0;
for (int i=1;i<=num;i++)
{
if (c[i-1]!=c[i]) cnt++;
h[c[i]]=cnt;
last[cnt]=c[i];
}
for (int i=1;i<=n;i++)
{
if (b[i].r==b[i-1].r) continue;
int k=h[b[i].r];
a[k]=h[b[i].l];
}
for (int i=1;i<=h[m];i++)
{
f[i]=f[i-1];
l[i]=l[i-1];
if (!a[i]) continue;
if (f[a[i]]+1>=f[i])
{
if (f[a[i]]+1>f[i])
{
f[i]=f[a[i]]+1;
if (f[a[i]]) l[i]=l[a[i]];
else l[i]=a[i];
}
else
{
if (f[a[i]]) l[i]=max(l[i],l[a[i]]);
else l[i]=max(l[i],a[i]);
}
}
}
ans=f[h[m]];
for (int i=h[m]+1;i<=h[2*m-1];i++)
{
if (!a[i]) continue;
if (l[a[i]]>=h[last[i]-m]) ans=max(ans,f[a[i]]+1);
}
printf("%d",ans);
}