题目大意
农夫约翰最近买了N(1≤N≤100,000)个干草堆,他把这些干草堆都放在家和农场之间的一条直路上,每个干草堆的位置各不相同。不幸的是,他忘记了他的奶牛贝里斯正外出吃草,贝里斯也许会被这些干草堆所限制住!干草堆j的大小是Sj,在Pj的位置上。贝里斯从一个不是干草堆的地方出发,他可以自由的在这条直线上移动,他不能越过干草堆。有一种特殊的情况, 他可以往一个方向连续跑了D的距离以后,他就可以积累足够的能量,然后就可以消除小于D的干草堆。当然了,在消除了一个干草堆以后,他就可以有更多的空间来跑步和积蓄能量了。当贝里斯成功消除了第一个或者最后一个干草堆的时候,他就可以获得自由了,请你计算使得贝里斯不能获得自由的初始位置的区间总和。
题目分析
观察题目,可以想到对于一段区间 i,模拟以区间 i 为起点并试图逃脱的过程,如果可以到达入一段已经判断为可以逃脱的区间 j ,那么区间 i 也是可以逃脱的。
这样我们可以从 1 到 n-1 枚举 i(第 i 段区间),用 l, r 记录这段区间目前所能到达最左边的草堆与最右边的草堆。
每次模拟消除草堆的过程,直到在当前 l, r 中无法消除 l与r 草堆 或 l==0 或 r==n 或 到达了一段可以逃脱的区间。这样复杂度几乎是 O(N)的。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN=1e5+10; 4 5 struct Node{ 6 int hei,pos; 7 }a[MAXN]; 8 inline bool cmp(Node x,Node y){ 9 return x.pos<y.pos; 10 } 11 12 int n,ans,len,l,r; 13 bool f[MAXN],flag; 14 inline bool Check(int x){ 15 len=a[x+1].pos-a[x].pos; 16 l=x;r=x+1; 17 while(1<=l&&r<=n){ 18 flag=false; 19 if(len>a[l].hei){ 20 flag=1; 21 --l; 22 if(f[l]){ 23 f[x]=true; 24 return true; 25 } 26 len+=(a[l+1].pos-a[l].pos); 27 } 28 if(len>a[r].hei){ 29 flag=1; 30 ++r; 31 if(f[r-1]){ 32 f[x]=1; 33 return true; 34 } 35 len+=(a[r].pos-a[r-1].pos); 36 } 37 if(!flag) return false; 38 } 39 return true; 40 } 41 int main(){ 42 scanf("%d",&n); 43 for(int i=1;i<=n;++i) 44 scanf("%d%d",&a[i].hei,&a[i].pos); 45 sort(a+1,a+n+1,cmp); 46 f[0]=1;f[n]=1; 47 for(int i=1;i<n;++i) 48 if(!Check(i)) 49 ans+=a[i+1].pos-a[i].pos; 50 printf("%d ",ans); 51 return 0; 52 }