B - 会議室の空き時間 / Available Time Slots for Meeting Rooms 解説 by admin 印刷ページ
Gemini 3.1 Pro (Thinking)概要
区間の共通部分を逐次求めていく問題です。各制限が追加されるたびに、利用可能な区間の左端と右端を更新し、その範囲に含まれる整数の個数を答えます。
考察
素朴なアプローチとして、利用可能な時刻を配列や集合(Set)などで直接管理しようとすると、時刻の最大値が \(10^9\) と非常に大きいため、メモリ制限(MLE)や時間制限(TLE)に引っかかってしまいます。
ここで、「区間と区間の共通部分もまた1つの区間になる」という性質に注目します。 現在の利用可能な区間が \([L, R]\) であり、新たな制限が \([l_i, r_i]\) であるとき、両方の条件を満たす区間は \([\max(L, l_i), \min(R, r_i)]\) となります。
具体例で考えてみましょう。 現在の区間が \([2, 8]\) で、新たな制限が \([5, 10]\) の場合、共通部分は \([\max(2, 5), \min(8, 10)] = [5, 8]\) となります。
このように、現在の左端 \(L\) と右端 \(R\) を変数として保持し、入力を受け取るたびに更新していけば、効率的に答えを求めることができます。 なお、制限が厳しくなり更新後に \(L > R\) となってしまった場合は、共通部分が存在しない(空集合)ため、利用可能な時刻の個数は \(0\) となります。
アルゴリズム
- 現在の利用可能な区間を表す変数 \(L\) と \(R\) を、初期値で設定します。
- \(N\) 個の利用制限について、順番に以下の処理を行います。
- 新たな制限の左端 \(l_i\) と右端 \(r_i\) を読み込みます。
- 左端 \(L\) を \(\max(L, l_i)\) に更新します(コード内では
if l > L: L = lと同義)。 - 右端 \(R\) を \(\min(R, r_i)\) に更新します(コード内では
if r < R: R = rと同義)。 - 利用可能な時刻の個数 \(count = R - L + 1\) を計算します。
- もし \(count < 0\) であれば、共通部分が存在しないため \(count = 0\) とします。
- \(count\) を答えとして記録します。
- 記録した答えを出力します。
計算量
- 時間計算量: \(O(N)\) 各制限に対する更新処理(\(\max\) や \(\min\) の計算)は \(O(1)\) で行えます。これを \(N\) 回繰り返すため、全体の時間計算量は \(O(N)\) となります。
- 空間計算量: \(O(N)\) 入力を一括で読み込むためのリストや、出力結果を保存するリストを使用するため、\(O(N)\) のメモリを使用します。
実装のポイント
入出力の高速化: Pythonでは、標準の
input()やprint()を何万回も繰り返すと実行時間制限(TLE)になることがあります。そのため、sys.stdin.read().split()で入力を一括で読み込み、出力もリストに貯めてから'\n'.join()で一気に出力する工夫をしています。空集合の判定: \(L\) と \(R\) が逆転して \(R - L + 1\) が負の値になった際、そのまま出力しないように注意が必要です。コード内では
if count < 0: count = 0として適切に処理しています。ソースコード
import sys
def main():
input_data = sys.stdin.read().split()
if not input_data:
return
L = int(input_data[0])
R = int(input_data[1])
N = int(input_data[2])
ans = []
idx = 3
for _ in range(N):
l = int(input_data[idx])
r = int(input_data[idx+1])
idx += 2
if l > L:
L = l
if r < R:
R = r
count = R - L + 1
if count < 0:
count = 0
ans.append(str(count))
sys.stdout.write('\n'.join(ans) + '\n')
if __name__ == '__main__':
main()
この解説は gemini-3.1-pro-thinking によって生成されました。
投稿日時:
最終更新: