目录
D. Jumping Through Segments
Problem - D - Codeforces
题目大意:
给你n个线段,每个线段有一个左边界和一个右边界,然后你每次可以走小于等于k的长度,要求第i次移动后落在第i个线段内,如果在第n次移动后落在第n个线段中,则算成功。求满足此要求下,最小的k值是多少。
思路:
如果k取很大,他一定能完成这个要求,则这个答案满足单调性,所以优先想到二分答案。
然后二分答案后,我们现在已经确定了每次能走的范围,所以我们很容易得到第i次移动后,能移动到第i个线段的那些区间,然后我们维护这个区间。
假设线段的左边界为li,线段的右边界为ri,第i-1次移动后能移动到的区间为a,b。有两种分布情况。
为什么不维护单个点,因为单个点,对于当前可能是优的,但对于下一次移动不一定优。
代码:
通过这六种分布情况来修改能移动到的区间
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.Scanner;
/**
* @ProjectName: study3
* @FileName: Ex45
* @author:HWJ
* @Data: 2023/12/5 23:16
*/
public class Ex45 {
public static void main(String[] args) throws IOException {
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
in.nextToken();
int t = (int) in.nval;
for (int o = 0; o < t; o++) {
in.nextToken();
int n = (int) in.nval;
int[][] arr = new int[n][2];
for (int i = 0; i < n; i++) {
in.nextToken();
arr[i][0] = (int) in.nval;
in.nextToken();
arr[i][1] = (int) in.nval;
}
int l = -1;
int r = 1000000000;
int ans = 0;
while (l <= r){
int mid = (l+r) >> 1;
int s = 0;
int e = 0;
boolean loop = true;
for (int i = 0; i < n; i++) {
if (arr[i][0] >= e){
e = Math.min(arr[i][1], e + mid);
if (e < arr[i][0]){
loop = false;
break;
}else {
s = arr[i][0];
}
} else if (arr[i][1] <= s) {
s = Math.max(s - mid, arr[i][0]);
if (s > arr[i][1]){
loop = false;
break;
}else {
e = arr[i][1];
}
}else if (s <= arr[i][0] && e >= arr[i][1]){
s = arr[i][0];
e = arr[i][1];
} else {
if (s >= arr[i][0] && e >= arr[i][1]){
s = Math.max(arr[i][0], s - mid);
e = arr[i][1];
}else if(s >= arr[i][0] && e < arr[i][1]){
s = Math.max(arr[i][0], s - mid);
e= Math.min(e + mid, arr[i][1]);
}
else{
e = Math.min(e + mid, arr[i][1]);
s = arr[i][0];
}
}
}
if (loop){
ans = mid;
r = mid - 1;
}else {
l = mid + 1;
}
}
System.out.println(ans);
}
}
}