C - りんご収穫 / Apple Harvest 解説 by admin
Gemini 3.0 Flash概要
直線上に並んだ \(N\) 本のりんごの木のうち、長さ \(K\) 以下の区間に含まれる木の最大本数を求める問題です。
考察
この問題を解くための重要なポイントは以下の3点です。
座標のソート: 与えられる木の座標 \(X_i\) はバラバラな順序で与えられます。区間内にある木を効率よく数えるためには、まず座標を昇順(小さい順)に並べ替えるのが定石です。ソートすることで、「連続する番号の木が、同じ区間に含まれる」という性質を利用できるようになります。
最適な区間のとり方: 「長さ \(K\) 以下の区間」は無限に考えられますが、最適な区間の左端 \(L\) は、必ずいずれかのりんごの木の座標 \(X_i\) と一致させて良いことがわかります。なぜなら、中途半端な位置から区間を始めても、左側にずらして木に合わせることで、損をすることはないからです。
素朴な方法の限界: 全ての木 \(i\) について、「木 \(i\) を左端としたときに、右端 \(X_i + K\) までに何本の木があるか」を数える方法を考えます。
- 各木に対して、他の全ての木をチェックすると \(O(N^2)\) の時間がかかります。
- 今回 \(N = 2 \times 10^5\) なので、\(N^2 = 4 \times 10^{10}\) となり、制限時間内に終わりません。 そこで、より効率的なしゃくとり法(または二分探索)が必要になります。
アルゴリズム
ソート済みの座標に対して、しゃくとり法(Two Pointers)を適用します。
- 木の座標 \(X\) を昇順にソートします。
- 区間の左端を指すポインタ
leftと、右端を指すポインタrightを用意します。 rightを \(0\) から \(N-1\) まで 1 つずつ進めながら、以下の操作を行います:- 現在の区間の長さ
X[right] - X[left]が \(K\) を超えている間、leftを右に進めます。 - 長さが \(K\) 以下になったら、その区間に含まれる木の数
right - left + 1を計算します。 - これまでの最大本数を更新します。
- 現在の区間の長さ
この方法では、left と right がそれぞれ一度ずつしか配列を走査しないため、非常に高速に動作します。
計算量
- 時間計算量: \(O(N \log N)\)
- 座標のソートに \(O(N \log N)\) かかります。
- しゃくとり法の部分は \(O(N)\) です。
- 全体としてソートが支配的となり、\(O(N \log N)\) となります。
- 空間計算量: \(O(N)\)
- 木の座標を保持するための配列に \(O(N)\) のメモリを使用します。
実装のポイント
ソートを忘れない: 入力された座標は順不同であるため、必ず最初に
sort()を行う必要があります。区間の長さの判定: 問題文の「区間の長さが \(K\) 以下」とは、右端の座標を \(R\)、左端を \(L\) としたとき \(R - L \leq K\) を満たすことを指します。コード上では
x[right] - x[left] > kの間、leftを進めることでこの条件を維持しています。大量の入力: \(N\) が大きいため、Python の場合は
sys.stdin.read().split()などを用いて高速に入力を読み込むのが望ましいです。ソースコード
import sys
def main():
# 入力を標準入力からすべて読み込む
input_data = sys.stdin.read().split()
if not input_data:
return
# N: りんごの木の本数, K: 区間の最大長
n = int(input_data[0])
k = int(input_data[1])
# x: 各りんごの木の座標
x = list(map(int, input_data[2:]))
# 座標を昇順にソートする
x.sort()
max_trees = 0
left = 0
# しゃくとり法(Two Pointers)を用いて、
# x[right] - x[left] <= k を満たす最大の個数 (right - left + 1) を求める
for right in range(n):
# 区間の長さが K を超える間、左端のポインタを進める
while x[right] - x[left] > k:
left += 1
# 現在の区間内に含まれる木の数
current_trees = right - left + 1
# 最大値を更新
if current_trees > max_trees:
max_trees = current_trees
# 結果を出力
print(max_trees)
if __name__ == "__main__":
main()
この解説は gemini-3-flash-preview によって生成されました。
投稿日時:
最終更新: