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;
}

posted on 2024-04-29 19:45  WHUStar  阅读(3)  评论(0编辑  收藏  举报