1041D - Glider(思维+二分+前缀和)

https://codeforces.com/problemset/problem/1041/D


思路:

可以发现,选择的起点在当前某个线段区间的左端点一定不会更差。

于是On枚举起点位置,快速找到其终点在的区间。下降的过程满足单调性,于是二分最终所在的区间。中间的check用前缀和处理区间的差值的累加就可以O1check了。

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=2e5+1000;
typedef long long LL;
inline LL read(){LL x=0,f=1;char ch=getchar();	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;}
struct P{
  LL l,r;
}a[maxn];
LL sum[maxn];
bool check(LL p,LL q,LL n,LL h){

    LL downdis=sum[q]-sum[p];
   /// cout<<"p="<<p<<" "<<"q="<<q<<" "<<"downdis="<<downdis<<"\n";
    if(h-downdis>0) return true;
    else return false;
}
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL n,h;cin>>n>>h;
  for(LL i=1;i<=n;i++){
    cin>>a[i].l>>a[i].r;
  }
  sum[1]=0;
  for(LL i=2;i<=n;i++){
    sum[i]=sum[i-1]+(a[i].l-a[i-1].r);
  }
  LL ans=0;
  for(LL i=1;i<=n;i++){///枚举起点,处于某个线段区间的左端点
      LL l=i;LL r=n;
      while(l<r){
          LL mid=(l+r+1)>>1;
          if(check(i,mid,n,h)) l=mid;
          else r=mid-1;
      }
     /// cout<<"i="<<i<<" "<<"l="<<l<<"\n";
      LL res1=a[l].r-a[i].l;
      LL temp=h;
      temp-=(sum[l]-sum[i]);
      res1+=temp;
      ans=max(ans,res1);
  }
  cout<<ans<<"\n";
return 0;
}

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/115266104
今日推荐