Skip to content

Commit 43adc62

Browse files
authored
Merge pull request #64 from myoshi2891/dev/macbook_pro
atcoder B07 - Convenience Store 2 差分配列(いもす法)+ 累積和
2 parents 8b3d565 + 356b90c commit 43adc62

6 files changed

Lines changed: 625 additions & 0 deletions

File tree

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// この問題では最大で `T = 500000`, `N = 500000` と非常に大きくなるため、**差分配列(いもす法)**+**累積和**を使って高速に処理する必要があります。
2+
3+
// ## ✅ Goによる回答コード(標準入力 & 高速出力対応)
4+
package main
5+
6+
import (
7+
"bufio"
8+
"fmt"
9+
"os"
10+
"strconv"
11+
"strings"
12+
)
13+
14+
func main() {
15+
reader := bufio.NewReaderSize(os.Stdin, 1<<20) // 1MB buffer
16+
scanner := bufio.NewScanner(reader)
17+
scanner.Split(bufio.ScanLines)
18+
19+
// Helper function to read one line and convert to int
20+
// readInt := func() int {
21+
// scanner.Scan()
22+
// val, _ := strconv.Atoi(scanner.Text())
23+
// return val
24+
// }
25+
26+
// First line: T (閉店時刻)
27+
scanner.Scan()
28+
T, _ := strconv.Atoi(scanner.Text())
29+
30+
// Second line: N (従業員数)
31+
scanner.Scan()
32+
N, _ := strconv.Atoi(scanner.Text())
33+
34+
// 差分配列の初期化
35+
cnt := make([]int, T+1)
36+
37+
// 各従業員の[L, R)を読み取り、差分配列に記録
38+
for i := 0; i < N; i++ {
39+
scanner.Scan()
40+
parts := strings.Fields(scanner.Text())
41+
L, _ := strconv.Atoi(parts[0])
42+
R, _ := strconv.Atoi(parts[1])
43+
cnt[L] += 1
44+
cnt[R] -= 1
45+
}
46+
47+
// 出力用バッファ
48+
writer := bufio.NewWriterSize(os.Stdout, 1<<20) // 1MB buffer
49+
defer writer.Flush()
50+
51+
// 累積和をとって出力
52+
current := 0
53+
for t := 0; t < T; t++ {
54+
current += cnt[t]
55+
fmt.Fprintln(writer, current)
56+
}
57+
}
58+
59+
// ## 📥 入力形式(例)
60+
61+
// ```text
62+
// 10
63+
// 7
64+
// 0 3
65+
// 2 4
66+
// 1 3
67+
// 0 3
68+
// 5 6
69+
// 5 6
70+
// 5 6
71+
// ```
72+
73+
// ---
74+
75+
// ## 📤 出力形式
76+
77+
// ```text
78+
// 2
79+
// 3
80+
// 4
81+
// 1
82+
// 0
83+
// 3
84+
// 0
85+
// 0
86+
// 0
87+
// 0
88+
// ```
89+
90+
// ---
91+
92+
// ## ✅ 説明
93+
94+
// ### データ構造
95+
96+
// | 変数名 | 型 | 内容 |
97+
// | --------- | ------- | --------------- |
98+
// | `T` | `int` | 営業時間(閉店時刻) |
99+
// | `N` | `int` | 従業員数 |
100+
// | `cnt` | `[]int` | 差分配列(サイズ `T+1`) |
101+
// | `current` | `int` | 時刻 t にいる人数の累積値 |
102+
103+
// ---
104+
105+
// ## ⏱ パフォーマンス
106+
107+
// * 計算量:O(N + T)
108+
// * メモリ:`cnt` 配列で最大 500001 要素 → 約 2MB
109+
// * 入出力:`bufio.NewReaderSize`, `NewWriterSize` を使用して高速化
110+
111+
// ## ✅ 実行方法(ターミナル)
112+
113+
// ファイル名 `main.go` で保存して以下を実行:
114+
115+
// ```bash
116+
// go run main.go < input.txt
117+
// ```
118+
119+
// またはコンパイルして実行:
120+
121+
// ```bash
122+
// go build main.go
123+
// ./main < input.txt
124+
// ```
125+
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// この問題は、\*\*差分配列(いもす法)\*\*を使うことで高速に解けます。
2+
// 各従業員が出勤する時に +1、退勤する時に -1 をして、累積和をとることで、
3+
// **時刻 t+0.5 に店内にいる人数**を O(N+T) で計算できます。
4+
5+
// ---
6+
7+
// ### 🔧 アプローチ(いもす法)
8+
9+
// * `cnt[i]` を「時刻 `i + 0.5` に店内にいる人数」とすると、
10+
11+
// * 従業員 `(L, R)` がいたとき:
12+
13+
// * `cnt[L] += 1`
14+
// * `cnt[R] -= 1`
15+
// * 最後に累積和を取って `cnt[0]` ~ `cnt[T-1]` を出力。
16+
17+
// ### ✅ JavaScript (Node.js, `fs`使用)
18+
19+
const fs = require('fs');
20+
21+
const input = fs.readFileSync('/dev/stdin', 'utf8').trim().split('\n');
22+
const T = parseInt(input[0], 10);
23+
const N = parseInt(input[1], 10);
24+
25+
// 差分配列の初期化
26+
const cnt = new Array(T + 1).fill(0);
27+
28+
// 各従業員の出退勤を処理
29+
for (let i = 0; i < N; i++) {
30+
const [L, R] = input[2 + i].split(' ').map(Number);
31+
cnt[L] += 1;
32+
cnt[R] -= 1;
33+
}
34+
35+
// 累積和をとって出力
36+
let current = 0;
37+
for (let t = 0; t < T; t++) {
38+
current += cnt[t];
39+
console.log(current);
40+
}
41+
42+
// ### 📈 実行時間とメモリ
43+
44+
// * 実行時間:O(N + T)
45+
// * メモリ使用量:配列 `cnt` のサイズは最大 500,001 要素 → 約 4MB 以下
46+
47+
// ---
48+
49+
// ### 🧠 図による解説(例)
50+
51+
// 入力:
52+
53+
// ```
54+
// T = 10, N = 3
55+
// [L, R] = [0,3], [2,4], [1,3]
56+
// ```
57+
58+
// 差分配列に追加:
59+
60+
// | 時刻 `t` | cnt\[t](差分) |
61+
// | ------ | ----------- |
62+
// | 0 | +1 |
63+
// | 1 | +1 |
64+
// | 2 | +1 |
65+
// | 3 | -3 |
66+
// | 4 | -1 |
67+
68+
// 累積和を取ると:
69+
70+
// | t | cnt (合計人数) |
71+
// | --- | ---------- |
72+
// | 0.5 | 1 |
73+
// | 1.5 | 2 |
74+
// | 2.5 | 3 |
75+
// | 3.5 | 0 |
76+
// | 4.5 | 0 |
77+
// | ... | ... |
78+
79+
// ---
80+
81+
// ### ✅ 注意
82+
83+
// * 差分配列の添字は `[0, T]` まで必要(R == T の人に対応)
84+
// * 出力は `console.log` を T 回実行して OK(T = 5e5 まで問題なし)
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<!-- この問題は最大で `T = 500000`, `N = 500000` と大きいため、**差分配列(いもす法)+ 累積和**を使って高速に処理します。
2+
3+
## ✅ PHPコード(型付き + 高速対応) -->
4+
5+
<?php
6+
7+
declare(strict_types=1);
8+
9+
/**
10+
* メイン処理関数
11+
*/
12+
function main(): void {
13+
$stdin = fopen('php://stdin', 'r');
14+
if ($stdin === false) {
15+
throw new RuntimeException("Failed to open stdin.");
16+
}
17+
18+
/** @var int $T 営業終了時間 */
19+
$T = (int)fgets($stdin);
20+
/** @var int $N 従業員数 */
21+
$N = (int)fgets($stdin);
22+
23+
/** @var array<int> $cnt 差分配列 */
24+
$cnt = array_fill(0, $T + 1, 0);
25+
26+
// 差分配列への反映
27+
for ($i = 0; $i < $N; $i++) {
28+
$line = fgets($stdin);
29+
if ($line === false) {
30+
throw new RuntimeException("Failed to read line.");
31+
}
32+
[$L, $R] = array_map('intval', explode(' ', trim($line)));
33+
$cnt[$L] += 1;
34+
$cnt[$R] -= 1;
35+
}
36+
37+
// 累積和と出力
38+
$current = 0;
39+
for ($t = 0; $t < $T; $t++) {
40+
$current += $cnt[$t];
41+
echo $current . "\n";
42+
}
43+
44+
fclose($stdin);
45+
}
46+
47+
main();
48+
49+
// ## 📥 入力例
50+
51+
// ```
52+
// 10
53+
// 7
54+
// 0 3
55+
// 2 4
56+
// 1 3
57+
// 0 3
58+
// 5 6
59+
// 5 6
60+
// 5 6
61+
// ```
62+
63+
// ## 📤 出力例
64+
65+
// ```
66+
// 2
67+
// 3
68+
// 4
69+
// 1
70+
// 0
71+
// 3
72+
// 0
73+
// 0
74+
// 0
75+
// 0
76+
// ```
77+
78+
// ## 🧠 解説
79+
80+
// ### 主な変数と型
81+
82+
// | 変数名 | 型 | 内容 |
83+
// | ---------- | ------------ | ------------- |
84+
// | `$T` | `int` | 営業終了時刻(閉店時刻) |
85+
// | `$N` | `int` | 従業員数 |
86+
// | `$cnt` | `array<int>` | 差分配列(サイズ T+1) |
87+
// | `$current` | `int` | 累積和で現在店内にいる人数 |
88+
// | `$stdin` | `resource` | 標準入力リソース |
89+
90+
// ## 🧮 計算量
91+
92+
// * 差分更新:O(N)
93+
// * 累積和:O(T)
94+
// * 合計:**O(N + T)**(最大でも 1,000,000 程度)→ 制約内で余裕
95+
96+
// ## ✅ 実行方法
97+
98+
// ローカルでテストする場合:
99+
100+
// ```bash
101+
// php main.php < input.txt
102+
// ```

0 commit comments

Comments
 (0)