Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions Algorithm/BinarySearch/atCoder/B11/B11.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// 以下は、**Go言語** を使って「配列 A の中で X より小さい要素がいくつあるか」を求めるプログラムです。
// 高速処理のため、**ソート + 二分探索** を用いています。

// ---

// ## ✅ アルゴリズムの概要

// * `sort.Ints(A)` で昇順にソート(前処理): `O(N log N)`
// * `sort.Search()` を使って各クエリに対する `X` 未満の個数を高速取得: `O(Q log N)`
// * 入力は `bufio.Scanner`、出力は `bufio.Writer` で高速処理

// ---

// ## ✅ Go 実装(型明示 + コメント付き)

// ```go
package main

import (
"bufio"
"fmt"
"os"
"sort"
"strconv"
)

func main() {
// 高速入出力設定
reader := bufio.NewScanner(os.Stdin)
reader.Split(bufio.ScanWords)
writer := bufio.NewWriter(os.Stdout)
defer writer.Flush()

// 整数読み取り関数
readInt := func() int {
reader.Scan()
val, _ := strconv.Atoi(reader.Text())
return val
}

// 入力 N
var N int = readInt()
A := make([]int, N)
for i := 0; i < N; i++ {
A[i] = readInt()
}

// ソート(前処理): O(N log N)
sort.Ints(A)

// 入力 Q
var Q int = readInt()
for i := 0; i < Q; i++ {
X := readInt()
// 二分探索(X未満の要素数)
count := sort.Search(len(A), func(i int) bool {
return A[i] >= X
})
fmt.Fprintln(writer, count)
}
}
// ```

// ---

// ## ✅ 処理時間とメモリ使用量

// ### 時間計算量

// | 処理内容 | 時間計算量 |
// | ---------- | -------------------- |
// | ソート処理 | O(N log N) |
// | クエリ Q 回の探索 | O(Q log N) |
// | 合計 | O(N log N + Q log N) |

// → 最大 `N, Q = 100000` でも `2 × 10⁶` 操作以下 → **1 秒以内で処理可能**

// ---

// ### メモリ使用量(推定)

// | 要素 | 概要 | メモリ使用量(概算) |
// | ------ | --------------- | ------------------ |
// | 配列 `A` | `[]int`, 最大10⁵個 | 約 0.8 MB(8バイト×10⁵) |
// | 出力 | `Writer` バッファなど | 数 KB〜数十 KB 程度 |
// | 合計 | 入力/出力含めて数 MB 程度 | ✅ 1024 MiB 制限に余裕あり |

// ---

// ## ✅ 入力例と出力

// ### 入力

// ```
// 5
// 1 3 3 3 1
// 2
// 4
// 3
// ```

// ### 出力

// ```
// 5
// 2
// ```

// ---

// ## ✅ 解法の特徴まとめ

// | 項目 | 内容 |
// | ------ | -------------------------------- |
// | ソート | `sort.Ints()`(O(N log N)) |
// | 探索 | `sort.Search()` で二分探索(X未満) |
// | 入出力高速化 | `bufio.Scanner` + `bufio.Writer` |
// | 実行時間 | 最大で 1 秒未満 |
// | メモリ | 数 MB 以下 |

89 changes: 89 additions & 0 deletions Algorithm/BinarySearch/atCoder/B11/B11.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// 以下は、**JavaScript (Node.js)** を用いた解法です。高速なクエリ応答のために、配列 `A` を **ソートして二分探索**を使い、各 `X` に対して「未満の要素数」を効率よく求めます。

// ## ✅ 方針

// 1. **配列 A を昇順にソート**しておく(O(N log N))。
// 2. 各クエリ `X` に対して **二分探索**で `A[i] < X` を満たす `i` の数を調べる(O(Q log N))。
// 3. `fs` モジュールで高速入出力を行う。

// ## ✅ コード
const fs = require("fs");

// 高速入力
const input = fs.readFileSync("/dev/stdin", "utf8").trim().split(/\s+/);

let idx = 0;
const N = parseInt(input[idx++]);
const A = [];

for (let i = 0; i < N; i++) {
A.push(parseInt(input[idx++]));
}

A.sort((a, b) => a - b); // 昇順ソート

const Q = parseInt(input[idx++]);
const results = [];

for (let q = 0; q < Q; q++) {
const X = parseInt(input[idx++]);
results.push(lowerBound(A, X)); // X 未満の個数
}

// 二分探索(lower_bound):X より小さい要素数
function lowerBound(arr, target) {
let left = 0;
let right = arr.length;
while (left < right) {
const mid = (left + right) >> 1;
if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}

// 出力(高速)
console.log(results.join("\n"));

// ## ✅ 処理時間・メモリの見積り

// * 時間計算量:

// * `A` のソート:`O(N log N)`
// * 各クエリに対して `O(log N)` → `Q log N`
// * 合計:`O(N log N + Q log N)` → 最大で約 `2×10^6` 回程度の操作 → 十分高速(1 秒以内)

// * 空間計算量:

// * `A` 配列と `results` の保存 → O(N + Q) 要素 → 約 800KB〜1MB 程度
// * メモリ制限(1024MiB)以内に収まる

// ---

// ## ✅ 入力例 1 の実行結果

// 入力:

// ```
// 15
// 83 31 11 17 32 19 23 37 43 47 53 61 67 5 55
// 5
// 10
// 20
// 30
// 40
// 50
// ```

// 出力:

// ```
// 1
// 4
// 5
// 8
// 10
// ```
115 changes: 115 additions & 0 deletions Algorithm/BinarySearch/atCoder/B11/B11.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<!-- 以下は、**PHP** を用いて「配列 A の中に X 未満の要素がいくつあるか」を効率的に求めるプログラムです。
処理時間とメモリ使用量を意識し、**ソート + 二分探索(lower\_bound)** を用います。

---

## ✅ アルゴリズム概要

1. **配列 A を昇順ソート**:`O(N log N)`
2. 各クエリ `X` に対して **二分探索**(`X` 未満の要素数)を求める:`O(Q log N)`
3. **標準入力**:`fgets()` + `explode()` を使用
4. **型注釈**:PHP 8.2 に準拠(`array<int>` や `int` 型)

---

## ✅ PHP 実装(PHP 8.2, 型付き)

```php -->
<?php

declare(strict_types=1);

// 二分探索: $arr の中で $target より小さい要素の個数を返す
function lower_bound(array $arr, int $target): int {
$left = 0;
$right = count($arr);
while ($left < $right) {
$mid = intdiv($left + $right, 2);
if ($arr[$mid] < $target) {
$left = $mid + 1;
} else {
$right = $mid;
}
}
return $left;
}

// 入力読み込み(高速)
$stdin = fopen('php://stdin', 'r');
$N = (int)fgets($stdin);
$A = array_map('intval', explode(' ', trim(fgets($stdin))));
sort($A); // 昇順ソート

$Q = (int)fgets($stdin);

// 結果配列
$results = [];

for ($i = 0; $i < $Q; $i++) {
$X = (int)fgets($stdin);
$count = lower_bound($A, $X);
$results[] = $count;
}

// 出力(高速)
echo implode("\n", $results) . "\n";
// ```

// ---

// ## ✅ 入力例の確認

// ### 入力:

// ```
// 5
// 1 3 3 3 1
// 2
// 4
// 3
// ```

// ### 出力:

// ```
// 5
// 2
// ```

// ---

// ## ✅ 処理時間・メモリの見積もり

// ### 時間計算量

// | 処理項目 | 計算量 |
// | --------- | ---------------------------------- |
// | 配列 A のソート | `O(N log N)` |
// | 各クエリの探索 | `O(Q log N)` |
// | 合計 | `O(N log N + Q log N)`(≒ 2×10⁶ 以内) |

// ✅ 最大入力 (`N = Q = 10^5`) に対しても **十分高速(1 秒以内)**

// ---

// ### メモリ使用量(推定)

// * `A`: 約 `100,000 × 4B = 約 400 KB`
// * `X` クエリ: 約 `400 KB`
// * `$results`: 最大 `400 KB`
// * その他合わせて:約 **1〜2 MB**

// ✅ 1024 MiB 制限に **十分収まる**

// ---

// ## ✅ 解法まとめ

// | 特徴 | 内容 |
// | ----- | ------------------------------- |
// | ソート | `sort($A)` で事前に準備(昇順) |
// | クエリ応答 | `lower_bound()` で `X` 未満の要素数を返す |
// | 時間効率 | `O(log N)` × Q で高速 |
// | メモリ効率 | 数MB程度で非常に良好 |

// ---
Loading