From 356b90c74fc94cbec311c356a81b7368af1957c0 Mon Sep 17 00:00:00 2001 From: myoshizumi Date: Thu, 3 Jul 2025 10:23:19 +0900 Subject: [PATCH] =?UTF-8?q?atcoder=20B07=20-=20Convenience=20Store=202=20?= =?UTF-8?q?=E5=B7=AE=E5=88=86=E9=85=8D=E5=88=97=EF=BC=88=E3=81=84=E3=82=82?= =?UTF-8?q?=E3=81=99=E6=B3=95=EF=BC=89+=20=E7=B4=AF=E7=A9=8D=E5=92=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Algorithm/DifferenceArray/atcoder/B07/B07.go | 125 ++++++++++++++++ Algorithm/DifferenceArray/atcoder/B07/B07.js | 84 +++++++++++ Algorithm/DifferenceArray/atcoder/B07/B07.php | 102 +++++++++++++ Algorithm/DifferenceArray/atcoder/B07/B07.py | 99 +++++++++++++ Algorithm/DifferenceArray/atcoder/B07/B07.ts | 76 ++++++++++ .../DifferenceArray/atcoder/B07/README.md | 139 ++++++++++++++++++ 6 files changed, 625 insertions(+) create mode 100644 Algorithm/DifferenceArray/atcoder/B07/B07.go create mode 100644 Algorithm/DifferenceArray/atcoder/B07/B07.js create mode 100644 Algorithm/DifferenceArray/atcoder/B07/B07.php create mode 100644 Algorithm/DifferenceArray/atcoder/B07/B07.py create mode 100644 Algorithm/DifferenceArray/atcoder/B07/B07.ts create mode 100644 Algorithm/DifferenceArray/atcoder/B07/README.md diff --git a/Algorithm/DifferenceArray/atcoder/B07/B07.go b/Algorithm/DifferenceArray/atcoder/B07/B07.go new file mode 100644 index 00000000..0d1215ac --- /dev/null +++ b/Algorithm/DifferenceArray/atcoder/B07/B07.go @@ -0,0 +1,125 @@ +// この問題では最大で `T = 500000`, `N = 500000` と非常に大きくなるため、**差分配列(いもす法)**+**累積和**を使って高速に処理する必要があります。 + +// ## ✅ Goによる回答コード(標準入力 & 高速出力対応) +package main + +import ( + "bufio" + "fmt" + "os" + "strconv" + "strings" +) + +func main() { + reader := bufio.NewReaderSize(os.Stdin, 1<<20) // 1MB buffer + scanner := bufio.NewScanner(reader) + scanner.Split(bufio.ScanLines) + + // Helper function to read one line and convert to int + // readInt := func() int { + // scanner.Scan() + // val, _ := strconv.Atoi(scanner.Text()) + // return val + // } + + // First line: T (閉店時刻) + scanner.Scan() + T, _ := strconv.Atoi(scanner.Text()) + + // Second line: N (従業員数) + scanner.Scan() + N, _ := strconv.Atoi(scanner.Text()) + + // 差分配列の初期化 + cnt := make([]int, T+1) + + // 各従業員の[L, R)を読み取り、差分配列に記録 + for i := 0; i < N; i++ { + scanner.Scan() + parts := strings.Fields(scanner.Text()) + L, _ := strconv.Atoi(parts[0]) + R, _ := strconv.Atoi(parts[1]) + cnt[L] += 1 + cnt[R] -= 1 + } + + // 出力用バッファ + writer := bufio.NewWriterSize(os.Stdout, 1<<20) // 1MB buffer + defer writer.Flush() + + // 累積和をとって出力 + current := 0 + for t := 0; t < T; t++ { + current += cnt[t] + fmt.Fprintln(writer, current) + } +} + +// ## 📥 入力形式(例) + +// ```text +// 10 +// 7 +// 0 3 +// 2 4 +// 1 3 +// 0 3 +// 5 6 +// 5 6 +// 5 6 +// ``` + +// --- + +// ## 📤 出力形式 + +// ```text +// 2 +// 3 +// 4 +// 1 +// 0 +// 3 +// 0 +// 0 +// 0 +// 0 +// ``` + +// --- + +// ## ✅ 説明 + +// ### データ構造 + +// | 変数名 | 型 | 内容 | +// | --------- | ------- | --------------- | +// | `T` | `int` | 営業時間(閉店時刻) | +// | `N` | `int` | 従業員数 | +// | `cnt` | `[]int` | 差分配列(サイズ `T+1`) | +// | `current` | `int` | 時刻 t にいる人数の累積値 | + +// --- + +// ## ⏱ パフォーマンス + +// * 計算量:O(N + T) +// * メモリ:`cnt` 配列で最大 500001 要素 → 約 2MB +// * 入出力:`bufio.NewReaderSize`, `NewWriterSize` を使用して高速化 + +// ## ✅ 実行方法(ターミナル) + +// ファイル名 `main.go` で保存して以下を実行: + +// ```bash +// go run main.go < input.txt +// ``` + +// またはコンパイルして実行: + +// ```bash +// go build main.go +// ./main < input.txt +// ``` + diff --git a/Algorithm/DifferenceArray/atcoder/B07/B07.js b/Algorithm/DifferenceArray/atcoder/B07/B07.js new file mode 100644 index 00000000..c01783da --- /dev/null +++ b/Algorithm/DifferenceArray/atcoder/B07/B07.js @@ -0,0 +1,84 @@ +// この問題は、\*\*差分配列(いもす法)\*\*を使うことで高速に解けます。 +// 各従業員が出勤する時に +1、退勤する時に -1 をして、累積和をとることで、 +// **時刻 t+0.5 に店内にいる人数**を O(N+T) で計算できます。 + +// --- + +// ### 🔧 アプローチ(いもす法) + +// * `cnt[i]` を「時刻 `i + 0.5` に店内にいる人数」とすると、 + +// * 従業員 `(L, R)` がいたとき: + +// * `cnt[L] += 1` +// * `cnt[R] -= 1` +// * 最後に累積和を取って `cnt[0]` ~ `cnt[T-1]` を出力。 + +// ### ✅ JavaScript (Node.js, `fs`使用) + +const fs = require('fs'); + +const input = fs.readFileSync('/dev/stdin', 'utf8').trim().split('\n'); +const T = parseInt(input[0], 10); +const N = parseInt(input[1], 10); + +// 差分配列の初期化 +const cnt = new Array(T + 1).fill(0); + +// 各従業員の出退勤を処理 +for (let i = 0; i < N; i++) { + const [L, R] = input[2 + i].split(' ').map(Number); + cnt[L] += 1; + cnt[R] -= 1; +} + +// 累積和をとって出力 +let current = 0; +for (let t = 0; t < T; t++) { + current += cnt[t]; + console.log(current); +} + +// ### 📈 実行時間とメモリ + +// * 実行時間:O(N + T) +// * メモリ使用量:配列 `cnt` のサイズは最大 500,001 要素 → 約 4MB 以下 + +// --- + +// ### 🧠 図による解説(例) + +// 入力: + +// ``` +// T = 10, N = 3 +// [L, R] = [0,3], [2,4], [1,3] +// ``` + +// 差分配列に追加: + +// | 時刻 `t` | cnt\[t](差分) | +// | ------ | ----------- | +// | 0 | +1 | +// | 1 | +1 | +// | 2 | +1 | +// | 3 | -3 | +// | 4 | -1 | + +// 累積和を取ると: + +// | t | cnt (合計人数) | +// | --- | ---------- | +// | 0.5 | 1 | +// | 1.5 | 2 | +// | 2.5 | 3 | +// | 3.5 | 0 | +// | 4.5 | 0 | +// | ... | ... | + +// --- + +// ### ✅ 注意 + +// * 差分配列の添字は `[0, T]` まで必要(R == T の人に対応) +// * 出力は `console.log` を T 回実行して OK(T = 5e5 まで問題なし) diff --git a/Algorithm/DifferenceArray/atcoder/B07/B07.php b/Algorithm/DifferenceArray/atcoder/B07/B07.php new file mode 100644 index 00000000..8633d822 --- /dev/null +++ b/Algorithm/DifferenceArray/atcoder/B07/B07.php @@ -0,0 +1,102 @@ + + + $cnt 差分配列 */ + $cnt = array_fill(0, $T + 1, 0); + + // 差分配列への反映 + for ($i = 0; $i < $N; $i++) { + $line = fgets($stdin); + if ($line === false) { + throw new RuntimeException("Failed to read line."); + } + [$L, $R] = array_map('intval', explode(' ', trim($line))); + $cnt[$L] += 1; + $cnt[$R] -= 1; + } + + // 累積和と出力 + $current = 0; + for ($t = 0; $t < $T; $t++) { + $current += $cnt[$t]; + echo $current . "\n"; + } + + fclose($stdin); +} + +main(); + +// ## 📥 入力例 + +// ``` +// 10 +// 7 +// 0 3 +// 2 4 +// 1 3 +// 0 3 +// 5 6 +// 5 6 +// 5 6 +// ``` + +// ## 📤 出力例 + +// ``` +// 2 +// 3 +// 4 +// 1 +// 0 +// 3 +// 0 +// 0 +// 0 +// 0 +// ``` + +// ## 🧠 解説 + +// ### 主な変数と型 + +// | 変数名 | 型 | 内容 | +// | ---------- | ------------ | ------------- | +// | `$T` | `int` | 営業終了時刻(閉店時刻) | +// | `$N` | `int` | 従業員数 | +// | `$cnt` | `array` | 差分配列(サイズ T+1) | +// | `$current` | `int` | 累積和で現在店内にいる人数 | +// | `$stdin` | `resource` | 標準入力リソース | + +// ## 🧮 計算量 + +// * 差分更新:O(N) +// * 累積和:O(T) +// * 合計:**O(N + T)**(最大でも 1,000,000 程度)→ 制約内で余裕 + +// ## ✅ 実行方法 + +// ローカルでテストする場合: + +// ```bash +// php main.php < input.txt +// ``` \ No newline at end of file diff --git a/Algorithm/DifferenceArray/atcoder/B07/B07.py b/Algorithm/DifferenceArray/atcoder/B07/B07.py new file mode 100644 index 00000000..3bda0030 --- /dev/null +++ b/Algorithm/DifferenceArray/atcoder/B07/B07.py @@ -0,0 +1,99 @@ +# この問題では、**いもす法(差分配列)+累積和**を用いて、最大入力でも高速に処理できます。 +# ## ✅ Pythonコード(型付き・高速対応) +from typing import List +import sys + +def main() -> None: + input = sys.stdin.readline + + T: int = int(input()) + N: int = int(input()) + + # 差分配列の初期化(サイズ T+1) + cnt: List[int] = [0] * (T + 1) + + # 差分の更新 + for _ in range(N): + L_str, R_str = input().split() + L: int = int(L_str) + R: int = int(R_str) + cnt[L] += 1 + cnt[R] -= 1 + + # 累積和を計算して出力 + current: int = 0 + output: List[str] = [] + for t in range(T): + current += cnt[t] + output.append(str(current)) + + # 出力(高速化のため一括) + print("\n".join(output)) + + +if __name__ == "__main__": + main() +# +# 📥 入力例 +# +# ``` +# 10 +# 7 +# 0 3 +# 2 4 +# 1 3 +# 0 3 +# 5 6 +# 5 6 +# 5 6 +# ``` +# +# --- +# +# 📤 出力例 +# +# ``` +# 2 +# 3 +# 4 +# 1 +# 0 +# 3 +# 0 +# 0 +# 0 +# 0 +# ``` +# +# --- +# +# 🧠 補足 +# +## 型アノテーション解説 +# +# | 変数 | 型 | 説明 | +# | --------- | ----------- | ------------------ | +# | `T` | `int` | 開店から閉店までの時間(0〜T-1) | +# | `N` | `int` | 従業員数 | +# | `cnt` | `List[int]` | 差分配列 | +# | `current` | `int` | 現在の従業員数(累積用) | +# | `output` | `List[str]` | 出力行のバッファ(高速出力用) | +# +# --- +# +# 🧮 計算量 +# +# * 差分更新:O(N) +# * 累積和+出力:O(T) +# * 合計:O(N + T) → 最大でも 10⁶ 程度、余裕で間に合います。 +# +# --- +# +# ✅ 実行方法(例) +# +# ファイル名を `main.py` にして、以下のように標準入力から実行できます: +# +# ```bash +# python3 main.py < input.txt +# ``` +# diff --git a/Algorithm/DifferenceArray/atcoder/B07/B07.ts b/Algorithm/DifferenceArray/atcoder/B07/B07.ts new file mode 100644 index 00000000..ace21107 --- /dev/null +++ b/Algorithm/DifferenceArray/atcoder/B07/B07.ts @@ -0,0 +1,76 @@ +// TypeScriptでこの問題を解く方法も、基本的に **いもす法(差分配列)+ 累積和** によって高速に処理します。 +// Node.jsの`fs`モジュールを使って標準入力を読み取ります。 + +// ## ✅ TypeScript版コード(`fs`使用) +import * as fs from "fs"; + +const input = fs.readFileSync("/dev/stdin", "utf8").trim().split("\n"); +const T = Number(input[0]); +const N = Number(input[1]); + +// 差分配列(T+1サイズで初期化) +const cnt: number[] = new Array(T + 1).fill(0); + +// 出勤・退勤を反映 +for (let i = 0; i < N; i++) { + const [L, R] = input[2 + i].split(" ").map(Number); + cnt[L] += 1; + cnt[R] -= 1; +} + +// 累積和で時刻 t+0.5 にいる人数を求める +let current = 0; +let result = ""; +for (let t = 0; t < T; t++) { + current += cnt[t]; + result += current + "\n"; +} + +// 出力(まとめて一括で) +process.stdout.write(result); + +// // ## 🔍 解説 + +// // ### 差分配列の考え方(いもす法) + +// // 各従業員 `(L, R)` に対して: + +// // * `cnt[L] += 1`(L.5 から入店) +// // * `cnt[R] -= 1`(R.5 から不在になる) + +// // これを累積すれば、各 `t+0.5` にいる人数がわかる。 + +// // --- + +// // ## 📈 計算量と制約内チェック + +// // * `cnt` のサイズは最大 `T + 1 = 500001` 要素 → 約4MB +// // * 時間計算量: + +// // * 差分更新:O(N) +// // * 累積和+出力:O(T) +// // * 合計:**O(N + T)** → 制約内(各最大 500,000) + +// // --- + +// // ## ✅ 実行環境補足 + +// // このTypeScriptコードは以下で実行できます: + +// // ```bash +// tsc main.ts +// node main.js < input.txt +// ``` + +// `tsconfig.json`が必要な場合は以下: + +// ```json +// { +// "compilerOptions": { +// "target": "ES2020", +// "module": "commonjs", +// "strict": true, +// "esModuleInterop": true +// } +// } +// ``` diff --git a/Algorithm/DifferenceArray/atcoder/B07/README.md b/Algorithm/DifferenceArray/atcoder/B07/README.md new file mode 100644 index 00000000..18227cbd --- /dev/null +++ b/Algorithm/DifferenceArray/atcoder/B07/README.md @@ -0,0 +1,139 @@ + +--- + +## 🏪 問題概要の再確認 + +### 📌 条件 + +* 開店時刻:`t = 0` +* 閉店時刻:`t = T` +* 各従業員 `i` は区間 `[Li, Ri)` の間だけ在店 +* 時刻 `t+0.5` に店内にいる人数を `T` 行出力 + +--- + +## 📥 入力例(図付き) + +``` +T = 10 +N = 7 +[0,3] +[2,4] +[1,3] +[0,3] +[5,6] +[5,6] +[5,6] +``` + +--- + +### 🧭 Step 1: 差分配列の更新(いもす法) + +#### 🧮 実行処理(TypeScript) + +```ts +cnt[L] += 1; +cnt[R] -= 1; +``` + +#### 📊 差分配列 `cnt` の初期状態(全て 0) + +| t | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | +| -- | - | - | - | - | - | - | - | - | - | - | -- | +| 差分 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | + +--- + +### ✏️ 差分更新後の `cnt` + +従業員の `[L, R]` を順に適用: + +| 従業員 | L | R | `cnt[L]++` | `cnt[R]--` | +| --- | - | - | ---------- | ---------- | +| 1 | 0 | 3 | +1 at 0 | -1 at 3 | +| 2 | 2 | 4 | +1 at 2 | -1 at 4 | +| 3 | 1 | 3 | +1 at 1 | -1 at 3 | +| 4 | 0 | 3 | +1 at 0 | -1 at 3 | +| 5 | 5 | 6 | +1 at 5 | -1 at 6 | +| 6 | 5 | 6 | +1 at 5 | -1 at 6 | +| 7 | 5 | 6 | +1 at 5 | -1 at 6 | + +#### 🧮 更新後の `cnt` 配列 + +| t | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | +| --- | - | - | - | -- | -- | - | -- | - | - | - | -- | +| cnt | 2 | 1 | 1 | -3 | -1 | 3 | -3 | 0 | 0 | 0 | 0 | + +--- + +## 🔄 Step 2: 累積和をとる + +```ts +let current = 0; +for (let t = 0; t < T; t++) { + current += cnt[t]; + console.log(current); +} +``` + +`current` を使って累積的に従業員の数を加算。 + +### 📊 累積和の流れと出力(= 各時刻 t+0.5 の人数) + +| t | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | +| -- | - | - | - | - | - | - | - | - | - | - | +| 累積 | 2 | 3 | 4 | 1 | 0 | 3 | 0 | 0 | 0 | 0 | + +--- + +## ⏰ イメージ図(時刻と人数) + +``` +時刻: 0 1 2 3 4 5 6 7 8 9 + |---|---|---|---|---|---|---|---|---| +人数(0.5): 2 3 4 1 0 3 0 0 0 0 +``` + +--- + +## ✅ 出力結果 + +``` +2 +3 +4 +1 +0 +3 +0 +0 +0 +0 +``` + +--- + +## 🧠 まとめ:各ステップの役割 + +| ステップ | 処理内容 | 計算量 | 内容 | +| ------ | -------------- | ---- | ---------------------------- | +| Step 1 | 差分配列 `cnt` の構築 | O(N) | 各 `[L, R)` に `+1, -1` | +| Step 2 | 累積和の計算(人数算出) | O(T) | `cnt[t]` を累積し、時刻 `t+0.5` に出力 | + +--- + +## ✍️ 備考 + +* `cnt` 配列はサイズ `T + 1` とすることで R = T の退勤も正しく処理 +* 出力はまとめて `process.stdout.write(result)` にすると高速化できる + +--- + +| [提出日時](https://atcoder.jp/contests/tessoku-book/submissions/me?desc=true&orderBy=created) | 問題 | ユーザ | 言語 | [得点](https://atcoder.jp/contests/tessoku-book/submissions/me?desc=true&orderBy=score) | [コード長](https://atcoder.jp/contests/tessoku-book/submissions/me?orderBy=source_length) | 結果 | [実行時間](https://atcoder.jp/contests/tessoku-book/submissions/me?orderBy=time_consumption) | [メモリ](https://atcoder.jp/contests/tessoku-book/submissions/me?orderBy=memory_consumption) | | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 2025-07-03 10:17:20 | [B07 - Convenience Store 2](https://atcoder.jp/contests/tessoku-book/tasks/math_and_algorithm_al) | [myoshizumi](https://atcoder.jp/users/myoshizumi) | [PHP (php 8.2.8)](https://atcoder.jp/contests/tessoku-book/submissions/me?f.Language=5016) | 1000 | 987 Byte | | 639 ms | 29068 KiB | [詳細](https://atcoder.jp/contests/tessoku-book/submissions/67248374) | +| 2025-07-03 10:11:51 | [B07 - Convenience Store 2](https://atcoder.jp/contests/tessoku-book/tasks/math_and_algorithm_al) | [myoshizumi](https://atcoder.jp/users/myoshizumi) | [Go (go 1.20.6)](https://atcoder.jp/contests/tessoku-book/submissions/me?f.Language=5002) | 1000 | 919 Byte | | 118 ms | 15736 KiB | [詳細](https://atcoder.jp/contests/tessoku-book/submissions/67248295) | +| 2025-07-03 10:07:39 | [B07 - Convenience Store 2](https://atcoder.jp/contests/tessoku-book/tasks/math_and_algorithm_al) | [myoshizumi](https://atcoder.jp/users/myoshizumi) | [Python (CPython 3.11.4)](https://atcoder.jp/contests/tessoku-book/submissions/me?f.Language=5055) | 1000 | 724 Byte | | 301 ms | 56448 KiB | [詳細](https://atcoder.jp/contests/tessoku-book/submissions/67248254) | +| 2025-07-03 09:49:03 | [B07 - Convenience Store 2](https://atcoder.jp/contests/tessoku-book/tasks/math_and_algorithm_al) | [myoshizumi](https://atcoder.jp/users/myoshizumi) | [TypeScript 5.1 (Node.js 18.16.1)](https://atcoder.jp/contests/tessoku-book/submissions/me?f.Language=5058) | 1000 | 661 Byte | | 472 ms | 134216 KiB | [詳細](https://atcoder.jp/contests/tessoku-book/submissions/67248019) | +| 2025-07-03 09:44:47 | [B07 - Convenience Store 2](https://atcoder.jp/contests/tessoku-book/tasks/math_and_algorithm_al) | [myoshizumi](https://atcoder.jp/users/myoshizumi) | [JavaScript (Node.js 18.16.1)](https://atcoder.jp/contests/tessoku-book/submissions/me?f.Language=5009) | 1000 | 546 Byte | | 1845 ms | 123988 KiB | [詳細](https://atcoder.jp/contests/tessoku-book/submissions/67247958) | \ No newline at end of file