在知乎内查看
题目
思路来源
官方题解
题解
一旦某个速度v满足,那么大于速度v的都满足,所以可以被二分,但是二分的check不好想,卡住了
最后去看了题解,其实维护的是,一个机器人在目标点收集硬币时,另一个机器人可能在的位置的范围
这个范围是一个连续的区间,并且在后面的变化过程中,也仍然会是连续的区间
所以,按时间顺序增序,
一开始,令其中一个机器人站在第一枚硬币上,那么另一个机器人的初始范围是 [ 1 , 1 0 9 ] [1,10^9] [1,109]
往后都维护这一个端点和一个区间
对于一枚新来的硬币,判断两个机器人是否可以接住这枚硬币,有四种情况:
-
如果端点所在的机器人能接住,而区间所在的机器人接不住,令端点所在的机器人去接,区间机器人只能往在这段时间往左右走,扩大活动范围
-
如果端点所在的机器人接不住,而区间所在的机器人能接住,令区间所在的机器人去接,并变成一个端点,原来端点所在的机器人在这段时间可以往左右走,扩大活动范围,变成一个区间
-
如果两个都能接住,那么谁去接都可以,实际就是1、2两种情况的并,然后发现1、2两个区间是有交的,那么他们的并集仍然是一个区间,所以还是维护一个端点和一个区间
-
如果都接不住,无解
事实上,只要同一秒不存在3个不同位置的机器人的话,总会是有解的
不过二分也统一了这种情况,v 大于 1 0 9 10^9 109 时认为没解就好了
代码
#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair<ll,ll> P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<<x<<" ";
#define dbg2(x) cerr<<(#x)<<":"<<x<<endl;
#define SZ(a) (int)(a.size())
#define sci(a) scanf("%d",&(a))
#define pt(a) printf("%d",a);
#define pte(a) printf("%d\n",a)
#define ptlle(a) printf("%lld\n",a)
#define debug(...) fprintf(stderr, __VA_ARGS__)
const int N=1e6+10;
const ll INF=1e9;
int t,n,c,x[N];
P a[N];
bool can(P x,P y,ll v){
return abs(x.se-y.se)<=v*abs(x.fi-y.fi);
}
bool ok(ll v){
int p=1;
ll l=1,r=INF;
rep(i,2,n){
ll T=a[i].fi-a[p].fi,d=T*v;
bool x=can(a[i],a[p],v),y=(l-d<=a[i].se && a[i].se<=r+d);
if(x && y){
l=min(l-d,a[p].se-d);
r=max(r+d,a[p].se+d);
}
else if(x){
l=l-d;
r=r+d;
}
else if(y){
l=a[p].se-d;
r=a[p].se+d;
}
else{
return 0;
}
p=i;
l=max(1ll,l);
r=min(INF,r);
}
return 1;
}
ll sol(){
sci(n);
rep(i,1,n){
scanf("%lld%lld",&a[i].fi,&a[i].se);
}
ll l=0,r=INF;
while(l<=r){
ll mid=(l+r)/2;
if(ok(mid))r=mid-1;
else l=mid+1;
}
if(l>INF)return -1;
return l;
}
int main(){
sci(t);
while(t--){
ptlle(sol());
}
return 0;
}