Codeforces Round 913 (Div. 3)

基本情况

A、B题秒了。

C题找了好几个规律,一开始一直找错,但是最后终于对的。

因为C题耗时太久,D题看都没看。准备先做一下再补题。

D. Jumping Through Segments

Problem - D - Codeforces

思路

看了一下,明显二分答案,但是 check 不会写。

正解巧妙。

不是针对一个点,而是针对一整个区间来扩充(一堆点)。

维护两个变量 \(L\)\(R\) 来表示这整个区间。

  • \(L\) 是这个东西能到达最大区间的左边界
    • 通过 \(\max(L - k, l_i)\) 来更新
      • \(L - k\),这个区间上所有的点能扩充的边界肯定是最左边的点扩充的最大,即 \(L - k\)
      • 但是也必须满足这一步的时候要到达指定区域,左边界 \(\geq l_i\)
  • \(R\) 是这个东西能到达最大区间的右边界
    • 通过 \(min(R + k, r_i)\) 来更新
      • \(R+k\),这个区间上所有的点能扩充的边界肯定是最右边的点扩充的最大,即 \(R + k\)
      • 但是也必须满足这一步的时候要到达指定区域,右边界 \(\leq r_i\)
  • 如果 \(L > R\)
    • 说明这个区间维护不下去了。
    • 那么这个 \(k\) 不合法

代码

#include<iostream>
#include<algorithm>
#include<cstdio>

const int N = 2e5 + 10;

struct Query{
	int l, r;
	void read()
	{
		std::cin >> l >> r;	
	} 
}a[N];

int l, r;
int mid;
int n;

bool check(int k)
{
	int t = 0;
	int L = 0, R = 0;
	for (int i = 1; i <= n; i++)
	{
		L = std::max(L - k, a[i].l);
		R = std::min(R + k, a[i].r);
		if (L > R) {printf("L = %d, R = %d, k = %d\n", L, R, k);return false;}
	}
	return true;
}

int main()
{
 	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout.tie(nullptr);
	int _;
	std::cin >> _;
	while(_--)
	{
		l = 0, r = 0;
		std::cin >> n;
		for (int i = 1; i <= n; i++) a[i].read(), r = std::max(r, a[i].r);
		while(l <= r)
		{
			mid = l + ((r - l) >> 1);
			if (check(mid))
				r = mid - 1;
			else
				l = mid + 1;
		}
		std::cout << r + 1 << std::endl;
	}
	return 0;
}
posted @ 2023-12-06 12:29  加固文明幻景  阅读(25)  评论(0编辑  收藏  举报