アルゴリズム概要

O(m)
時間計算量
O(1)
空間計算量
total // n
核心式
差分配列不要
重要な洞察

問題要約

n 個のキャンディ瓶(初期値 0)に対して m 回の操作を行う。
各操作 [a, b, v] は 「インデックス a 以上 b 以下の全瓶に v 個追加」を意味する。
全操作後の 平均キャンディ数の床関数 を返せ。

制約
  • 1 ≤ n ≤ 107
  • 1 ≤ m ≤ 105
  • 1 ≤ a ≤ b ≤ n
  • 0 ≤ v ≤ 109

サンプル検証

操作 瓶1 瓶2 瓶3 瓶4 瓶5
初期 0 0 0 0 0
[1,2,100] 100 100 0 0 0
[2,5,100] 100 200 100 100 100
[3,4,100] 100 200 200 200 100
合計→平均 800 ÷ 5 = 160

ステップバイステップ解説

Python 実装

🏆 競技プログラミング向け
エラーハンドリング省略・最速実装
🏢 業務開発向け
型安全・バリデーション付き
from __future__ import annotations
import os
from typing import List


# ─────────────────────────────────────────────────────────
# 競技プログラミング向け実装
# Time:  O(m)  ← 操作数のみ(n に非依存)
# Space: O(1)  ← 追加配列なし
#
# 核心式:
#   S = Σ v_i × (b_i - a_i + 1)
#   answer = floor(S / n) = S // n
# ─────────────────────────────────────────────────────────
def solve(n: int, operations: List[List[int]]) -> int:
    # Δ S = v × (b - a + 1)  を全操作分加算
    total: int = sum(v * (b - a + 1) for a, b, v in operations)
    # S // n は floor(S/n) と等価(S≥0, n>0 保証)
    return total // n


# ─────────────────────────────────────────────────────────
# 業務開発向け実装(型安全・バリデーション付き)
# ─────────────────────────────────────────────────────────
def solve_production(n: int, operations: List[List[int]]) -> int:
    """
    全操作後の平均キャンディ数の床関数を返す。

    Args:
        n:          瓶の数 (1 ≤ n ≤ 10^7)
        operations: [[a, b, v], ...] 形式の操作リスト

    Returns:
        floor(全瓶の平均キャンディ数) の整数値

    Raises:
        ValueError: n が正でない、または操作が制約違反の場合
    """
    if not isinstance(n, int) or n <= 0:
        raise ValueError(f"n は正の整数である必要があります: {n}")
    if not operations:
        return 0

    total: int = 0
    for op in operations:
        if len(op) != 3:
            raise ValueError(f"操作は 3 要素のリストである必要があります: {op}")
        a, b, v = op
        if not (1 <= a <= b <= n):
            raise ValueError(f"無効なインデックス範囲 [{a}, {b}](n={n})")
        if v < 0:
            raise ValueError(f"v は非負である必要があります: {v}")
        total += v * (b - a + 1)   # Δ S = v × (b - a + 1)

    return total // n              # floor(S / n)


# ─────────────────────────────────────────────────────────
# HackerRank エントリポイント
# ─────────────────────────────────────────────────────────
if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')

    first_multiple_input = input().rstrip().split()
    n = int(first_multiple_input[0])
    m = int(first_multiple_input[1])

    operations: List[List[int]] = []
    for _ in range(m):
        operations.append(list(map(int, input().rstrip().split())))

    result = solve(n, operations)
    fptr.write(str(result) + '\n')
    fptr.close()

処理フローチャート

開始 ① 入力受付 n(瓶の数) m(操作数) operations[ ] ② 総和 S を 0 で初期化 total = 0 ③ 各操作 [a, b, v] に対してループ 操作の寄与を計算 Δ S = v × ( b − a + 1 ) 総和に加算 S = S + Δ S ④ 核心式:直接総和計算 S = Σ v_i × ( b_i − a_i + 1 ) 差分配列展開・復元をスキップ → O(m) で完結 ⑤ 平均の床関数を計算 answer = S // n = floor( S / n ) Python の // は S≥0, n>0 のとき floor と等価 ⑥ 結果を返す return answer 終了

フローの解説:
1. 入力受付: n(瓶の数)、m(操作数)、全操作リストを受け取る
2. 初期化: 総和 S を 0 で初期化(追加配列は不要)
3. 操作ループ: 各操作の寄与 Δ S = v × (b - a + 1) を S に加算
4. 核心式: 差分配列展開をスキップ、O(m) で完結する直接総和計算
5. 床関数: S // n で平均の floor を計算
6. 出力: 結果を返す

計算量分析

アプローチ 時間計算量 空間計算量 備考
✅ 直接総和(本解) O(m) O(1) n に非依存。最適解。
差分配列 O(n + m) O(n) n=10⁷ で無駄に遅い
愚直シミュレーション O(n × m) O(n) 最大 10¹² 操作 → TLE
なぜ差分配列が不要か

差分配列は各瓶の個別の最終値を求めるときに必要。
今回必要なのは総和だけ

総和 = Σ(各瓶の値)= Σ 操作の寄与
= Σ v × (b - a + 1)
これは O(m) で直接計算できる。

Python bignum の安全性

最大総和 = 10⁹ × 10⁷ × 10⁵ = 10²¹
CPython の int は任意精度 bignum なので
オーバーフローの心配は一切不要。

// 演算子は bignum にも正確に動作する。