Jumping Through Segments
题目:
链接:
https://www.luogu.com.cn/problem/CF1907D
大致思路:
二分模拟
关键点:
①确定二分区间:最小值为第一次跳的左边界,最大值为连续两个线段的最远值(注意,应该有四种情况:左1减右1,左2减右1,左1减右2,左2减右2,取绝对值);
②确定如何模拟:递推:假定跳跃长度≤k(mid),那么下一个最远就是ra+mid,最近就是la-mid,然后看有没有交集:如果没有就返回false,改变左值为mid+1;如果有就更新la和ra为能跳到的边界(就是交集)。
其中:初值:la= xdlst[0].left
,ra = min(xdlst[0].right, mid)
就是说第一步一定能有左边界,然后右边界和mid的最小值。
代码:
#include<iostream>
#include<vector>
#include<algorithm>
#include<math.h>
#include<sstream>
#include<string>
#include<string.h>
#include<iomanip>
#include<stdlib.h>
#include<map>
#include<queue>
#include<limits.h>
#include<climits>
#include<fstream>
#include<stack>
#include<set>
typedef long long ll;
using namespace std;
const int N = 2e5 + 10;
int n;
struct xd
{
ll left, right;
}xdlst[N];
bool jd(ll mid)
{
ll la = xdlst[0].left, ra = min(xdlst[0].right, mid);
int id = 1;
while (id < n)
{
ll lnext = max(la - mid, (ll)0), rnext = ra + mid;
if (lnext > xdlst[id].right or rnext < xdlst[id].left)return false;
else
{
la = max(xdlst[id].left, lnext), ra = min(xdlst[id].right, rnext);
}
id++;
}
return true;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t; cin >> t;
while (t--)
{
cin >> n;
ll maxn = 0;
for (int i = 0; i < n; i++)
{
cin >> xdlst[i].left >> xdlst[i].right;
if (i)maxn = max(abs(xdlst[i].left - xdlst[i - 1].right), max(abs(xdlst[i].right - xdlst[i - 1].right),
max(abs(xdlst[i].left - xdlst[i - 1].left),max(maxn,abs( xdlst[i].right - xdlst[i - 1].left)))));
}
ll minn = xdlst[0].left;
while (minn < maxn)
{
ll mid = minn + (maxn - minn) / 2;
if (jd(mid))//if mid low:cannot,return true;
maxn = mid;
else minn = 1 + mid;
}
cout << minn << endl;
}
return 0;
}