ARC060 E Tak and Hotels 倍增

题目链接

题意:
给你 n n n个坐标,要求每次移动不超过 l l l,并且每次移动后一定要到这 n n n个坐标中的某一个。有 q q q次询问,每次询问一对点 a , b a,b a,b,求从 a a a b b b最少移动几次。 n , q &lt; = 1 e 5 n,q&lt;=1e5 n,q<=1e5

题解:
首先我们可以用一个two pointer在O(n)的时间内算出以每个点为起点走不超过 l l l的距离最多走到哪个点。感觉网上好多都说要二分,但是我感觉二分还没有two pointer好写,而且跑得还慢。求完只后我们可以对刚才的数组倍增,求出每个点操作 2 i 2^i 2i步最多到达的编号是多少。这样对于每次询问,从 a a a b b b和从 b b b a a a是等价的,所以我们设 b &gt; = a b&gt;=a b>=a。我们从 a a a先跳到小于 b b b的可以跳到的最后一个点,然后再跳一次就能跳到 b b b了,于是就可以用倍增每次 l o g n logn logn的复杂度来回答询问了。最终复杂度 O ( n + q l o g n ) O(n+qlogn) O(n+qlogn)

代码:

#include <bits/stdc++.h>
using namespace std;

int n,q,a[100010],f[100010][21],l,r;
int main()
{
 scanf("%d",&n);
 for(int i=1;i<=n;++i)
 scanf("%d",&a[i]);
 scanf("%d",&l);
 r=1;
 for(int i=1;i<=n;++i)
 {
  while(a[r+1]-a[i]<=l&&r+1<=n)
  ++r;
  f[i][0]=r;
 }
 for(int i=n;i>=1;--i)
 {
  for(int j=1;j<=20;++j)
  f[i][j]=f[f[i][j-1]][j-1];
 }
 scanf("%d",&q);
 for(int i=1;i<=q;++i)
 {
  int x,y,ans=0;
  scanf("%d%d",&x,&y);
  if(x>y)
  swap(x,y);
  for(int j=20;j>=0;--j)
  {
   if(f[x][j]<y)
   {
    x=f[x][j];
    ans+=(1<<j);
   }   
  }
  ans+=1;
  printf("%d\n",ans);
 }
 return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值