题目链接:
题目大意:
给出一些树的位置和高度,每棵树可以砍倒,覆盖[xi−hi,xi]或者覆盖[xi,xi+hi],或者不砍倒,问最多砍倒多少棵树?
题目分析:
我们记录dp[i]表示选取到i棵树的时候用的最短的区间长度。每次枚举每棵树,二分到最大的不超过当前树位置的个数,然后利用当前树的信息更新dp[i]。如果当前树左倒或者右倒会压到临近的树,那么当前树不能砍。
AC代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define MAX 100007
using namespace std;
int dp[MAX];
int x[MAX];
int h[MAX];
int n;
const int INF = 2e9+7;
int bsearch ( int x )
{
int l = 0 , r = n , mid;
while ( l != r )
{
mid = (l+r+1)>>1;
if ( dp[mid] < x ) l=mid;
else r = mid-1;
}
return l;
}
int main ( )
{
while ( ~scanf ("%d" , &n ))
{
for ( int i = 1 ; i <= n ; i++ )
dp[i] = INF;
dp[0] = -INF;
for ( int i = 1 ; i <= n ; i++ )
scanf ("%d%d" , &x[i] , &h[i] );
for ( int i = 1 ; i <= n ; i++ )
{
int id = bsearch ( x[i] )+1;
if ( i == n || x[i]+h[i] < x[i+1] )
dp[id] = min ( dp[id] , x[i]+h[i] );
id = bsearch ( x[i]-h[i] )+1;
if ( i == 1 || x[i]-h[i] > x[i-1] )
dp[id] = min ( dp[id] , x[i] );
}
int ans;
for ( int i = n ; i >= 1 ; i-- )
if ( dp[i] != INF )
{
ans = i;
break;
}
printf ( "%d\n" , ans );
}
}