B - 靴下のペア作り / Pairing Socks 解説 by admin
GPT 5.2 High概要
靴下の色の濃さ \(A_i\) を使い、差の絶対値が \(K\) 以下となるように 2 枚ずつペアを作るとき、作れるペア数の最大値を求めます。
考察
ペア条件は「2枚の差が \(K\) 以下」で、しかも靴下は使い回せません。最大個数を作るには「なるべく多くの靴下を無駄にしない組み方」が必要です。
ここで重要な観察は次の通りです:
- 靴下を色の濃さで 昇順にソートすると、近い値同士が隣に集まります。
- ソート後に、ある靴下 \(A[i]\) を誰かと組ませるなら、最も相性が良い候補は近い値(特に隣の \(A[i+1]\))です。
素朴に「全ての組み合わせから最適なマッチングを探す」ようなことをすると、組み合わせは膨大(最大 \(2\times 10^5\) 枚)なので現実的に間に合いません(TLEになります)。
ではどうするかというと、ソートして左から順に見ていき、
- 隣同士 \(A[i], A[i+1]\) の差が \(K\) 以下なら この2枚をペアにする
- そうでなければ \(A[i]\) は 誰とも組めないので捨てて次へ
という貪欲法で最大を作れます。
なぜ「差が \(K\) を超えるとき \(A[i]\) を捨ててよい」のか? - ソート済みなので、\(A[i+1]-A[i] > K\) なら、\(j>i+1\) に対しては \(A[j]\ge A[i+1]\) より \(A[j]-A[i] \ge A[i+1]-A[i] > K\) となり、後ろのどの靴下とも条件を満たせません。 - よって \(A[i]\) は必ず余るため、先へ進むのが最適です。
また、\(A[i+1]-A[i]\le K\) のとき隣同士でペアにしてよいのか? - \(A[i]\) をより遠い相手(\(A[i+2]\) 以降)と組ませると、間の \(A[i+1]\) が余りやすくなり、ペア数が減る可能性が高いです。 - 隣同士で組むのが最も「詰めて」ペアを作れるため、結果的に最大個数になります。
具体例: - \(A=[1,2,10,11]\), \(K=1\) - \((1,2)\) は差1でOK → 1ペア - \((10,11)\) も差1でOK → 合計2ペア(最大)
- \(A=[1,3,4]\), \(K=1\)
- \((1,3)\) は差2でNG → 1は誰とも組めないので捨てる
- \((3,4)\) は差1でOK → 1ペア(最大)
アルゴリズム
- 配列 \(A\) を昇順にソートする。
- インデックス \(i=0\) から開始し、以下を繰り返す(\(i+1 < N\) の間):
- もし \(A[i+1]-A[i] \le K\) なら、\((A[i], A[i+1])\) をペアにして答えを \(+1\)、\(i\) を \(2\) 増やす(両方消費)。
- そうでなければ \(A[i]\) はペアにできないので、\(i\) を \(1\) 増やす(\(A[i]\) を捨てる)。
- 得られたペア数を出力する。
これは「ソート + 1回走査(2ポインタ的)」のシンプルな貪欲法です。
計算量
- 時間計算量: \(O(N\log N)\)(ソートが支配的、走査は \(O(N)\))
- 空間計算量: \(O(N)\)(配列を保持。ソートも含めこの程度)
実装のポイント
\(N\) が最大 \(2\times 10^5\) なので、入力は
sys.stdin.buffer.read()などで高速に読むと安全です。ソート後は差分判定が \(A[i+1]-A[i]\) で済みます(昇順なので絶対値不要)。
ループ条件を
while i + 1 < N:にして、常に「次の要素が存在する」ことを保証します。ソースコード
import sys
def main():
data = list(map(int, sys.stdin.buffer.read().split()))
if not data:
return
N, K = data[0], data[1]
A = data[2:]
A.sort()
i = 0
ans = 0
while i + 1 < N:
if A[i + 1] - A[i] <= K:
ans += 1
i += 2
else:
i += 1
print(ans)
if __name__ == "__main__":
main()
この解説は gpt-5.2-high によって生成されました。