C - Flapping Takahashi 解説
by
Nyaan
まず、高橋君の移動としてあり得るものは様々ですから、高橋君の行動を 1 点読みして計算していくのは大変そうです。
そこで、高橋君が飛ぶことが出来る高度の範囲を考えてみることにします。すると、高橋君がこれまでの目標を全て達成しながら飛ぶことが出来る高度の範囲は、
- 空である、すなわちどのように飛行しても高橋君はこれまでの目標を満たせないか、あるいは
- ある \(L \leq U\) を用いて \(L \leq x \leq U\) あるいは \(L \lt x \leq U\) と表せるか
のどちらかです。
後者が「\(L \leq x \leq U\) あるいは \(L \lt x \leq U\)」という中途半端な条件になっているのは「高橋君は高度 \(0\) 以下 にいられない」という制約によるものです。この条件を 「高橋君は高度 \(1\) 未満 にいられない」と厳しくしても答えが変わらないことが証明できるので(理由の説明は省略します)、簡単のためこちらの条件で問題を解きましょう。そうすると、高橋君がこれまでの目標を全て達成しながら飛ぶことが出来る高度の範囲は、
- 空であるか、あるいは
- ある \(L \leq U\) を用いて \(L \leq x \leq U\) と表せるか
のどちらかになることが証明できます。
理由を説明します。時刻 \(t\) に高橋君が \(L_t \leq x \leq U_t\) の範囲を飛行できたとします。この時、時刻が \(d\) 進んで時刻 \(t+d\) になった時の高橋君が飛行可能な範囲は以下のように計算できます:
- 時刻が \(d\) 進むと \(d\) だけ移動できるので \(L = L_t - d, U = U_t + d\) とする。
- 高度 \(1\) 未満は飛行できないので \(L = \max(1, L)\) とする。
- 入力で与えられる目標 \(t_i, l_i, u_i\) について \(t_i = t+d\) となる \(i\) が存在したとする。すると高橋君は \(l_i \leq x \leq u_i\) の範囲にいる必要があるので \(L = \max(L, l_i), U = \min(U, u_i)\) とする。この操作によって \(L \gt U\) となった場合、高橋君が飛行可能な範囲は空となる。
この計算によって得られる高橋君が飛行可能な範囲は空であるか \(L \leq x \leq U\) を満たすかのどちらかです。よって前述の内容が証明できました。
よって、各目標の時刻について高橋君が飛行可能な範囲が空にならないかを判定すればよいことが確認できるので、これを計算すれば最終的な高橋君が飛行可能な範囲が空かどうかが計算できます。計算量は \(\mathrm{O}(N)\) で十分高速です。
- 実装例(C++)
#include <iostream>
#include <vector>
using namespace std;
void solve() {
int N, H;
cin >> N >> H;
vector<int> T(N), L(N), U(N);
for (int i = 0; i < N; i++) cin >> T[i] >> L[i] >> U[i];
int t_prev = 0, l = H, u = H;
for (int i = 0; i < N; i++) {
int d = T[i] - t_prev;
l -= d, u += d;
t_prev = T[i];
l = max(l, L[i]);
u = min(u, U[i]);
if (l > u) {
cout << "No\n";
return;
}
}
cout << "Yes\n";
}
int main() {
cin.tie(0)->sync_with_stdio(0);
int T;
cin >> T;
while (T--) solve();
}
投稿日時:
最終更新:
