Codeforces Round 913 (Div. 3)
基本情况
A、B题秒了。
C题找了好几个规律,一开始一直找错,但是最后终于对的。
因为C题耗时太久,D题看都没看。准备先做一下再补题。
D. Jumping Through Segments
思路
看了一下,明显二分答案,但是 check
不会写。
正解巧妙。
不是针对一个点,而是针对一整个区间来扩充(一堆点)。
维护两个变量 \(L\) 、\(R\) 来表示这整个区间。
- \(L\) 是这个东西能到达最大区间的左边界
- 通过 \(\max(L - k, l_i)\) 来更新
- \(L - k\),这个区间上所有的点能扩充的边界肯定是最左边的点扩充的最大,即 \(L - k\)。
- 但是也必须满足这一步的时候要到达指定区域,左边界 \(\geq l_i\)
- 通过 \(\max(L - k, l_i)\) 来更新
- \(R\) 是这个东西能到达最大区间的右边界
- 通过 \(min(R + k, r_i)\) 来更新
- \(R+k\),这个区间上所有的点能扩充的边界肯定是最右边的点扩充的最大,即 \(R + k\)。
- 但是也必须满足这一步的时候要到达指定区域,右边界 \(\leq r_i\)
- 通过 \(min(R + k, 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;
}