目 录CONTENT

文章目录

Jumping Through Segments【二分】

千年的霜雪
2024-01-23 / 0 评论 / 0 点赞 / 9 阅读 / 0 字 / 正在检测是否收录...

Jumping Through Segments

题目描述

Polycarp is designing a level for a game. The level consists of n segments on the number line, where the i -th segment starts at the point with coordinate l_i and ends at the point with coordinate r_i .

The player starts the level at the point with coordinate 0 . In one move, they can move to any point that is within a distance of no more than k . After their i -th move, the player must land within the i -th segment, that is, at a coordinate x such that l_i \le x \le r_i . This means:

  • After the first move, they must be inside the first segment (from l_1 to r_1 );
  • After the second move, they must be inside the second segment (from l_2 to r_2 );
  • ...
  • After the n -th move, they must be inside the n -th segment (from l_n to r_n ).

The level is considered completed if the player reaches the n -th segment, following the rules described above. After some thought, Polycarp realized that it is impossible to complete the level with some values of k .

Polycarp does not want the level to be too easy, so he asks you to determine the minimum integer k with which it is possible to complete the level.

输入格式

The first line contains a single integer t ( 1 \le t \le 10^4 )—the number of test cases. Descriptions of the test cases follow.

The first line of each test case contains a single integer n ( 1 \le n \le 2 \cdot 10^5 )—the number of segments in the level.

The following n lines.

The i -th line contain two integers l_i and r_i ( 0 \le l_i \le r_i \le 10^9 )—the boundaries of the i -th segment. Segments may intersect.

It is guaranteed that the sum of n over all test cases does not exceed 2 \cdot 10^5 .

输出格式

For each test case, output a single integer—the minimum value of k with which it is possible to complete the level.

样例 #1

样例输入 #1

4
5
1 5
3 4
5 6
8 10
0 1
3
0 2
0 1
0 3
3
3 8
10 18
6 11
4
10 20
0 5
15 17
2 2

样例输出 #1

7
0
5
13

提示

In the third example, the player can make the following moves:

  • Move from point 0 to point 5 ( 3 \le 5 \le 8 );
  • Move from point 5 to point 10 ( 10 \le 10 \le 18 );
  • Move from point 10 to point 7 ( 6 \le 7 \le 11 ).

Note that for the last move, the player could have chosen not to move and still complete the level.

二分思路

这题本身想到二分并不难,但是check函数并不好写,因为k只是每步的一个最大值,具体每步的最优解并不能确定。我最开始正向想了很久,都没办法解决每步具体走多远的问题,而且还牵扯到是正向走还是反向走。最后看了题解才明白。

这题既然正向思考不通过,那么可以反向思考,想每一步走后都会落在哪里,求出每步可能走到的范围,与下一步要求的范围求交集,为空则该方案不可行。

对于每步的范围,设 l , r 为目前可走到的左右边界,( lnxt, rnxt )为下一步的要求范围,则 ( l - k, r + k ) 即为下一步可走到的范围,则 ( l - k, r + k ) \cap ( lnxt, rnxt )即为下一步按题意能到达的范围

求并集

这里还有个小问题,并集怎么求。
其实只要找到两集合左端点的最大值,和右端点的最小值,最后用得到的新的左右端点的大小判断是否为空就行了。

l = max(l, li[i]);
r = min(r, ri[i]);
if (l > r) return false;

AC代码

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <iostream>

using namespace std;

const int MAX = 2e5 + 10;

int li[MAX];
int ri[MAX];//每步要求区域

bool check(int x, int n)
{
    int l = 0, r = x;//可到达区域 
    for (int i = 1; i <= n; i++)
    {
        l = max(l, li[i]);
        r = min(r, ri[i]);
        if (l > r) return false;
        l -= x;
        r += x;
    }
    return true;
}

int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int n = 0;
        scanf("%d", &n);//步数
        for (int i = 1; i <= n; i++) scanf("%d %d", &li[i], &ri[i]);

        int l = 0, r = 1e9, mid = 0;
        while (l < r)
        {
            mid = l + r >> 1;
            if (check(mid, n)) r = mid;
            else l = mid + 1;
        }//二分

        printf("%d\n", l);
    }
    return 0;
}
0

评论区