Skip to content

Commit e0224ae

Browse files
authored
Merge pull request #68 from myoshi2891/dev/macbook_pro
atcoder B11 - Binary Search 2
2 parents 98bf5bf + 877d09a commit e0224ae

9 files changed

Lines changed: 1008 additions & 0 deletions

File tree

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// 以下は、**Go言語** を使って「配列 A の中で X より小さい要素がいくつあるか」を求めるプログラムです。
2+
// 高速処理のため、**ソート + 二分探索** を用いています。
3+
4+
// ---
5+
6+
// ## ✅ アルゴリズムの概要
7+
8+
// * `sort.Ints(A)` で昇順にソート(前処理): `O(N log N)`
9+
// * `sort.Search()` を使って各クエリに対する `X` 未満の個数を高速取得: `O(Q log N)`
10+
// * 入力は `bufio.Scanner`、出力は `bufio.Writer` で高速処理
11+
12+
// ---
13+
14+
// ## ✅ Go 実装(型明示 + コメント付き)
15+
16+
// ```go
17+
package main
18+
19+
import (
20+
"bufio"
21+
"fmt"
22+
"os"
23+
"sort"
24+
"strconv"
25+
)
26+
27+
func main() {
28+
// 高速入出力設定
29+
reader := bufio.NewScanner(os.Stdin)
30+
reader.Split(bufio.ScanWords)
31+
writer := bufio.NewWriter(os.Stdout)
32+
defer writer.Flush()
33+
34+
// 整数読み取り関数
35+
readInt := func() int {
36+
reader.Scan()
37+
val, _ := strconv.Atoi(reader.Text())
38+
return val
39+
}
40+
41+
// 入力 N
42+
var N int = readInt()
43+
A := make([]int, N)
44+
for i := 0; i < N; i++ {
45+
A[i] = readInt()
46+
}
47+
48+
// ソート(前処理): O(N log N)
49+
sort.Ints(A)
50+
51+
// 入力 Q
52+
var Q int = readInt()
53+
for i := 0; i < Q; i++ {
54+
X := readInt()
55+
// 二分探索(X未満の要素数)
56+
count := sort.Search(len(A), func(i int) bool {
57+
return A[i] >= X
58+
})
59+
fmt.Fprintln(writer, count)
60+
}
61+
}
62+
// ```
63+
64+
// ---
65+
66+
// ## ✅ 処理時間とメモリ使用量
67+
68+
// ### 時間計算量
69+
70+
// | 処理内容 | 時間計算量 |
71+
// | ---------- | -------------------- |
72+
// | ソート処理 | O(N log N) |
73+
// | クエリ Q 回の探索 | O(Q log N) |
74+
// | 合計 | O(N log N + Q log N) |
75+
76+
// → 最大 `N, Q = 100000` でも `2 × 10⁶` 操作以下 → **1 秒以内で処理可能**
77+
78+
// ---
79+
80+
// ### メモリ使用量(推定)
81+
82+
// | 要素 | 概要 | メモリ使用量(概算) |
83+
// | ------ | --------------- | ------------------ |
84+
// | 配列 `A` | `[]int`, 最大10⁵個 | 約 0.8 MB(8バイト×10⁵) |
85+
// | 出力 | `Writer` バッファなど | 数 KB〜数十 KB 程度 |
86+
// | 合計 | 入力/出力含めて数 MB 程度 | ✅ 1024 MiB 制限に余裕あり |
87+
88+
// ---
89+
90+
// ## ✅ 入力例と出力
91+
92+
// ### 入力
93+
94+
// ```
95+
// 5
96+
// 1 3 3 3 1
97+
// 2
98+
// 4
99+
// 3
100+
// ```
101+
102+
// ### 出力
103+
104+
// ```
105+
// 5
106+
// 2
107+
// ```
108+
109+
// ---
110+
111+
// ## ✅ 解法の特徴まとめ
112+
113+
// | 項目 | 内容 |
114+
// | ------ | -------------------------------- |
115+
// | ソート | `sort.Ints()`(O(N log N)) |
116+
// | 探索 | `sort.Search()` で二分探索(X未満) |
117+
// | 入出力高速化 | `bufio.Scanner` + `bufio.Writer` |
118+
// | 実行時間 | 最大で 1 秒未満 |
119+
// | メモリ | 数 MB 以下 |
120+
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// 以下は、**JavaScript (Node.js)** を用いた解法です。高速なクエリ応答のために、配列 `A` を **ソートして二分探索**を使い、各 `X` に対して「未満の要素数」を効率よく求めます。
2+
3+
// ## ✅ 方針
4+
5+
// 1. **配列 A を昇順にソート**しておく(O(N log N))。
6+
// 2. 各クエリ `X` に対して **二分探索**で `A[i] < X` を満たす `i` の数を調べる(O(Q log N))。
7+
// 3. `fs` モジュールで高速入出力を行う。
8+
9+
// ## ✅ コード
10+
const fs = require("fs");
11+
12+
// 高速入力
13+
const input = fs.readFileSync("/dev/stdin", "utf8").trim().split(/\s+/);
14+
15+
let idx = 0;
16+
const N = parseInt(input[idx++]);
17+
const A = [];
18+
19+
for (let i = 0; i < N; i++) {
20+
A.push(parseInt(input[idx++]));
21+
}
22+
23+
A.sort((a, b) => a - b); // 昇順ソート
24+
25+
const Q = parseInt(input[idx++]);
26+
const results = [];
27+
28+
for (let q = 0; q < Q; q++) {
29+
const X = parseInt(input[idx++]);
30+
results.push(lowerBound(A, X)); // X 未満の個数
31+
}
32+
33+
// 二分探索(lower_bound):X より小さい要素数
34+
function lowerBound(arr, target) {
35+
let left = 0;
36+
let right = arr.length;
37+
while (left < right) {
38+
const mid = (left + right) >> 1;
39+
if (arr[mid] < target) {
40+
left = mid + 1;
41+
} else {
42+
right = mid;
43+
}
44+
}
45+
return left;
46+
}
47+
48+
// 出力(高速)
49+
console.log(results.join("\n"));
50+
51+
// ## ✅ 処理時間・メモリの見積り
52+
53+
// * 時間計算量:
54+
55+
// * `A` のソート:`O(N log N)`
56+
// * 各クエリに対して `O(log N)` → `Q log N`
57+
// * 合計:`O(N log N + Q log N)` → 最大で約 `2×10^6` 回程度の操作 → 十分高速(1 秒以内)
58+
59+
// * 空間計算量:
60+
61+
// * `A` 配列と `results` の保存 → O(N + Q) 要素 → 約 800KB〜1MB 程度
62+
// * メモリ制限(1024MiB)以内に収まる
63+
64+
// ---
65+
66+
// ## ✅ 入力例 1 の実行結果
67+
68+
// 入力:
69+
70+
// ```
71+
// 15
72+
// 83 31 11 17 32 19 23 37 43 47 53 61 67 5 55
73+
// 5
74+
// 10
75+
// 20
76+
// 30
77+
// 40
78+
// 50
79+
// ```
80+
81+
// 出力:
82+
83+
// ```
84+
// 1
85+
// 4
86+
// 5
87+
// 8
88+
// 10
89+
// ```
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<!-- 以下は、**PHP** を用いて「配列 A の中に X 未満の要素がいくつあるか」を効率的に求めるプログラムです。
2+
処理時間とメモリ使用量を意識し、**ソート + 二分探索(lower\_bound)** を用います。
3+
4+
---
5+
6+
## ✅ アルゴリズム概要
7+
8+
1. **配列 A を昇順ソート**:`O(N log N)`
9+
2. 各クエリ `X` に対して **二分探索**(`X` 未満の要素数)を求める:`O(Q log N)`
10+
3. **標準入力**:`fgets()` + `explode()` を使用
11+
4. **型注釈**:PHP 8.2 に準拠(`array<int>` や `int` 型)
12+
13+
---
14+
15+
## ✅ PHP 実装(PHP 8.2, 型付き)
16+
17+
```php -->
18+
<?php
19+
20+
declare(strict_types=1);
21+
22+
// 二分探索: $arr の中で $target より小さい要素の個数を返す
23+
function lower_bound(array $arr, int $target): int {
24+
$left = 0;
25+
$right = count($arr);
26+
while ($left < $right) {
27+
$mid = intdiv($left + $right, 2);
28+
if ($arr[$mid] < $target) {
29+
$left = $mid + 1;
30+
} else {
31+
$right = $mid;
32+
}
33+
}
34+
return $left;
35+
}
36+
37+
// 入力読み込み(高速)
38+
$stdin = fopen('php://stdin', 'r');
39+
$N = (int)fgets($stdin);
40+
$A = array_map('intval', explode(' ', trim(fgets($stdin))));
41+
sort($A); // 昇順ソート
42+
43+
$Q = (int)fgets($stdin);
44+
45+
// 結果配列
46+
$results = [];
47+
48+
for ($i = 0; $i < $Q; $i++) {
49+
$X = (int)fgets($stdin);
50+
$count = lower_bound($A, $X);
51+
$results[] = $count;
52+
}
53+
54+
// 出力(高速)
55+
echo implode("\n", $results) . "\n";
56+
// ```
57+
58+
// ---
59+
60+
// ## ✅ 入力例の確認
61+
62+
// ### 入力:
63+
64+
// ```
65+
// 5
66+
// 1 3 3 3 1
67+
// 2
68+
// 4
69+
// 3
70+
// ```
71+
72+
// ### 出力:
73+
74+
// ```
75+
// 5
76+
// 2
77+
// ```
78+
79+
// ---
80+
81+
// ## ✅ 処理時間・メモリの見積もり
82+
83+
// ### 時間計算量
84+
85+
// | 処理項目 | 計算量 |
86+
// | --------- | ---------------------------------- |
87+
// | 配列 A のソート | `O(N log N)` |
88+
// | 各クエリの探索 | `O(Q log N)` |
89+
// | 合計 | `O(N log N + Q log N)`(≒ 2×10⁶ 以内) |
90+
91+
// ✅ 最大入力 (`N = Q = 10^5`) に対しても **十分高速(1 秒以内)**
92+
93+
// ---
94+
95+
// ### メモリ使用量(推定)
96+
97+
// * `A`: 約 `100,000 × 4B = 約 400 KB`
98+
// * `X` クエリ: 約 `400 KB`
99+
// * `$results`: 最大 `400 KB`
100+
// * その他合わせて:約 **1〜2 MB**
101+
102+
// ✅ 1024 MiB 制限に **十分収まる**
103+
104+
// ---
105+
106+
// ## ✅ 解法まとめ
107+
108+
// | 特徴 | 内容 |
109+
// | ----- | ------------------------------- |
110+
// | ソート | `sort($A)` で事前に準備(昇順) |
111+
// | クエリ応答 | `lower_bound()` で `X` 未満の要素数を返す |
112+
// | 時間効率 | `O(log N)` × Q で高速 |
113+
// | メモリ効率 | 数MB程度で非常に良好 |
114+
115+
// ---

0 commit comments

Comments
 (0)