时空限制 1000ms / 128MB
题目描述
有一条奶牛冲出了围栏,来到了一处圣地(对于奶牛来说),上面用牛语写着一段文字。
现用汉语翻译为:
有N个区间,每个区间x,y表示提供的x~y共y-x+1堆优质牧草。你可以选择任意区间但不能有重复的部分。
对于奶牛来说,自然是吃的越多越好,然而奶牛智商有限,现在请你帮助他。
输入格式:
第一行,N,如题
接下来N行,每行一个数x,y,如题
输出格式:
一个数,最多能吃到的牧草堆数
说明
1<=n<=150000
0<=x<=y<=3000000
题目分析
先将所有草堆以右端点为第一关键字排序
d
p
[
i
]
dp[i]
dp[i]表示考虑前
i
i
i堆草能获得的最大数量
那么有dp转移
d
p
[
i
]
=
m
a
x
(
d
p
[
i
−
1
]
,
R
i
−
L
i
+
1
,
m
a
x
(
d
p
[
j
]
+
R
i
−
L
i
+
1
)
)
(
1
<
=
j
<
i
,
R
j
<
L
i
)
dp[i]=max(dp[i-1],\ R_i-L_i+1,\ max(dp[j]+R_i-L_i+1))(1<=j<i,\ R_j<L_i)
dp[i]=max(dp[i−1], Ri−Li+1, max(dp[j]+Ri−Li+1))(1<=j<i, Rj<Li)
显然
d
p
[
i
]
dp[i]
dp[i]一定是不下降的
若不存在
j
j
j满足
(
1
<
=
j
<
i
,
R
j
<
L
i
)
(1<=j<i,\ R_j<L_i)
(1<=j<i, Rj<Li),则
d
p
[
i
]
=
m
a
x
(
d
p
[
i
−
1
]
,
R
i
−
L
i
+
1
)
dp[i]=max(dp[i-1],\ R_i-L_i+1)
dp[i]=max(dp[i−1], Ri−Li+1)
也就是要么不选第
i
i
i堆,要么只选第
i
i
i堆
而如果存在这样的
j
j
j
直接枚举
j
j
j去更新是
O
(
n
2
)
O(n^2)
O(n2)的,肯定T
但注意到
d
p
[
i
]
dp[i]
dp[i]的不下降性
所以直接二分寻找满足
1
<
=
j
<
i
1<=j<i
1<=j<i且离
i
i
i最近的
j
j
j即可
#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const int maxn=200010;
int n;
struct node{int ll,rr;}rem[maxn];
bool cmp(node a,node b){return a.rr==b.rr?a.ll<b.ll:a.rr<b.rr;}
int dp[maxn];
int find(int x)
{
int ll=1,rr=x,mid,ans=-1;
while(ll<rr)
{
mid=ll+rr>>1;
if(rem[mid].rr<rem[x].ll) ans=mid,ll=mid+1;
else rr=mid;
}
return ans;
}
int main()
{
n=read();
for(int i=1;i<=n;++i)
rem[i].ll=read(),rem[i].rr=read();
sort(rem+1,rem+1+n,cmp);
dp[1]=rem[1].rr-rem[1].ll+1;
for(int i=2;i<=n;++i)
{
dp[i]=max(dp[i-1],rem[i].rr-rem[i].ll+1);
int j=find(i);
if(j!=-1) dp[i]=max(dp[i],dp[j]+rem[i].rr-rem[i].ll+1);
}
printf("%d",dp[n]);
return 0;
}