From f1d50fc10dbca2ecab93136b86120fb849d3c509 Mon Sep 17 00:00:00 2001 From: myoshizumi Date: Tue, 1 Jul 2025 18:47:12 +0900 Subject: [PATCH 1/2] =?UTF-8?q?atcoder=20A76=20-=20River=20Crossing=20?= =?UTF-8?q?=E5=BA=A7=E6=A8=99=E5=9C=A7=E7=B8=AE=20+=20=E5=8B=95=E7=9A=84?= =?UTF-8?q?=E8=A8=88=E7=94=BB=E6=B3=95=EF=BC=88DP=EF=BC=89=20+=20Fenwick?= =?UTF-8?q?=20Tree=20(BIT)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FenwickTree/atcoder/A76/A76.go | 126 +++++++++++++++++ .../FenwickTree/atcoder/A76/A76.js | 114 +++++++++++++++ .../FenwickTree/atcoder/A76/A76.php | 131 ++++++++++++++++++ .../FenwickTree/atcoder/A76/A76.py | 103 ++++++++++++++ .../FenwickTree/atcoder/A76/A76.ts | 105 ++++++++++++++ .../FenwickTree/atcoder/A76/README.md | 129 +++++++++++++++++ DataStructures/Trees/Heap/Deadline | 19 --- 7 files changed, 708 insertions(+), 19 deletions(-) create mode 100644 DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/A76.go create mode 100644 DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/A76.js create mode 100644 DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/A76.php create mode 100644 DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/A76.py create mode 100644 DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/A76.ts create mode 100644 DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/README.md delete mode 100644 DataStructures/Trees/Heap/Deadline diff --git a/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/A76.go b/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/A76.go new file mode 100644 index 00000000..7ff2ea62 --- /dev/null +++ b/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/A76.go @@ -0,0 +1,126 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "sort" + "strconv" +) + +const MOD = 1_000_000_007 + +type FenwickTree struct { + n int + data []int +} + +func NewFenwickTree(n int) *FenwickTree { + return &FenwickTree{ + n: n, + data: make([]int, n+2), + } +} + +func (ft *FenwickTree) Add(i, x int) { + i++ + for i <= ft.n+1 { + ft.data[i] = (ft.data[i] + x) % MOD + i += i & -i + } +} + +func (ft *FenwickTree) Sum(i int) int { + i++ + res := 0 + for i > 0 { + res = (res + ft.data[i]) % MOD + i -= i & -i + } + return res +} + +func (ft *FenwickTree) RangeSum(l, r int) int { + return (ft.Sum(r) - ft.Sum(l-1) + MOD) % MOD +} + +func lowerBound(a []int, x int) int { + return sort.Search(len(a), func(i int) bool { return a[i] >= x }) +} + +func upperBound(a []int, x int) int { + return sort.Search(len(a), func(i int) bool { return a[i] > x }) +} + +func main() { + scanner := bufio.NewScanner(os.Stdin) + scanner.Split(bufio.ScanWords) // 単語(スペース区切り)単位で読み取り + + readInt := func() int { + scanner.Scan() + n, _ := strconv.Atoi(scanner.Text()) + return n + } + + N := readInt() + W := readInt() + L := readInt() + R := readInt() + + X := make([]int, N) + for i := 0; i < N; i++ { + X[i] = readInt() + } + + // 全地点(スタート0、足場、ゴールW)をリストアップ + positions := append([]int{0}, X...) + positions = append(positions, W) + sort.Ints(positions) + + posIndex := make(map[int]int) + for i, v := range positions { + posIndex[v] = i + } + + n := len(positions) + dp := make([]int, n) + dp[0] = 1 + + ft := NewFenwickTree(n) + ft.Add(0, 1) + + for i := 1; i < n; i++ { + cur := positions[i] + left := cur - R + right := cur - L + + li := lowerBound(positions, left) + ri := upperBound(positions, right) - 1 + + if li <= ri { + val := ft.RangeSum(li, ri) + dp[i] = val + ft.Add(i, val) + } + } + + fmt.Println(dp[n-1]) +} + +// Go 解法で 20件の入力で ランタイムエラー(panic) が発生するとのこと、原因として考えられるのは以下のいずれかです: + +// ❗️ 原因候補 +// bufio.Scanner の 2行しか読んでいない +// 実際には N が大きくなると 複数行に分かれて入力される 可能性がある。 +// つまり "5 65 7 37" の次に "5 15 30 50 55" でなく、改行を含む複数行に X が分割されている可能性がある。 +// Xstr := strings.Fields(scanner.Text()) だけで全 N 要素を取得できない。 + +// ✅ 修正方針 +// N 個の X[i] を読み切るまで ループで scanner.Scan() を繰り返す +// X := make([]int, N) を安全に埋める + +// ✅ 修正点まとめ +// 修正箇所 内容 +// scanner.Split(...) 単語単位で int を逐次読み取り可能に +// readInt() 関数 scanner.Scan() + strconv.Atoi() のラッパー +// X[i] = readInt() 必ず N 件読み切るようループで読み取り \ No newline at end of file diff --git a/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/A76.js b/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/A76.js new file mode 100644 index 00000000..39bf1d78 --- /dev/null +++ b/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/A76.js @@ -0,0 +1,114 @@ +const readline = require("readline"); + +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout +}); + +const MOD = 1_000_000_007; + +rl.once("line", (line1) => { + const [N, W, L, R] = line1.trim().split(" ").map(Number); + rl.once("line", (line2) => { + const X = line2.trim().split(" ").map(Number); + + // 座標圧縮: 0 (スタート), 全ての足場, W (ゴール) + const positions = [0, ...X, W]; + positions.sort((a, b) => a - b); + const indexMap = new Map(); + positions.forEach((v, i) => indexMap.set(v, i)); + + const n = positions.length; + const dp = Array(n).fill(0); + dp[0] = 1; + + // Fenwick Tree 実装 + class FenwickTree { + constructor(n) { + this.n = n; + this.tree = Array(n + 2).fill(0); + } + + add(i, x) { + i++; + while (i <= this.n + 1) { + this.tree[i] = (this.tree[i] + x) % MOD; + i += i & -i; + } + } + + sum(i) { + i++; + let res = 0; + while (i > 0) { + res = (res + this.tree[i]) % MOD; + i -= i & -i; + } + return res; + } + + rangeSum(l, r) { + return (this.sum(r) - this.sum(l - 1) + MOD) % MOD; + } + } + + const ft = new FenwickTree(n); + ft.add(0, 1); + + for (let i = 1; i < n; i++) { + const cur = positions[i]; + const left = cur - R; + const right = cur - L; + + // 二分探索で到達可能な範囲 [left, right] を index に変換 + let li = lowerBound(positions, left); + let ri = upperBound(positions, right) - 1; + + if (li <= ri) { + const val = ft.rangeSum(li, ri); + dp[i] = val; + ft.add(i, val); + } + } + + console.log(dp[n - 1]); + rl.close(); + }); +}); + +// 二分探索: lower_bound +function lowerBound(arr, x) { + let left = 0, right = arr.length; + while (left < right) { + let mid = (left + right) >> 1; + if (arr[mid] < x) left = mid + 1; + else right = mid; + } + return left; +} + +// 二分探索: upper_bound +function upperBound(arr, x) { + let left = 0, right = arr.length; + while (left < right) { + let mid = (left + right) >> 1; + if (arr[mid] <= x) left = mid + 1; + else right = mid; + } + return left; +} + + +// ✅ 解法概要(JavaScript) +// 出発点 0 と終点 W を含めた すべてのジャンプ可能な地点 を 昇順で管理。 +// ジャンプ可能距離 [L, R] に対して、ある地点 pos[i] に到達するために、直前のどの地点 pos[j] からジャンプすればいいかを 二分探索で特定。 +// 各地点の到達方法数 dp[i] を高速に合計管理するために、Binary Indexed Tree (Fenwick Tree) を使う。 + +// 🧠 考慮するポイント +// JavaScript では大きな座標 (W ≤ 10^9) を扱うが、実際にジャンプできる点は最大でも N + 2 個しかないため、インデックス圧縮が使える。 +// dp[i]: i 番目の位置に到達する方法の数(mod 1e9+7) +// dp[0] = 1(スタート地点) + +// ⏱️ 計算量 +// 座標圧縮・二分探索・Fenwick Tree 操作:すべて O(N log N) +// N ≤ 150000 でも十分間に合います。 \ No newline at end of file diff --git a/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/A76.php b/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/A76.php new file mode 100644 index 00000000..a514e7fe --- /dev/null +++ b/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/A76.php @@ -0,0 +1,131 @@ +n = $n; + $this->tree = array_fill(0, $n + 2, 0); + } + + public function add(int $i, int $x): void + { + $i++; + while ($i <= $this->n + 1) { + $this->tree[$i] = ($this->tree[$i] + $x) % MOD; + $i += $i & -$i; + } + } + + public function sum(int $i): int + { + $i++; + $res = 0; + while ($i > 0) { + $res = ($res + $this->tree[$i]) % MOD; + $i -= $i & -$i; + } + return $res; + } + + public function rangeSum(int $l, int $r): int + { + return ($this->sum($r) - $this->sum($l - 1) + MOD) % MOD; + } +} + +function lowerBound(array $arr, int $x): int +{ + $left = 0; + $right = count($arr); + while ($left < $right) { + $mid = intdiv($left + $right, 2); + if ($arr[$mid] < $x) { + $left = $mid + 1; + } else { + $right = $mid; + } + } + return $left; +} + +function upperBound(array $arr, int $x): int +{ + $left = 0; + $right = count($arr); + while ($left < $right) { + $mid = intdiv($left + $right, 2); + if ($arr[$mid] <= $x) { + $left = $mid + 1; + } else { + $right = $mid; + } + } + return $left; +} + +function main(): void +{ + [$N, $W, $L, $R] = array_map('intval', explode(' ', trim(fgets(STDIN)))); + $Xs = array_map('intval', explode(' ', trim(fgets(STDIN)))); + + // 圧縮対象: 0, 足場, W + $positions = array_merge([0], $Xs, [$W]); + sort($positions); + $n = count($positions); + + // 位置→インデックスマップ(未使用でもOK) + $posToIndex = []; + foreach ($positions as $i => $val) { + $posToIndex[$val] = $i; + } + + $dp = array_fill(0, $n, 0); + $dp[0] = 1; + + $ft = new FenwickTree($n); + $ft->add(0, 1); + + for ($i = 1; $i < $n; $i++) { + $cur = $positions[$i]; + $left = $cur - $R; + $right = $cur - $L; + + $li = lowerBound($positions, $left); + $ri = upperBound($positions, $right) - 1; + + if ($li <= $ri) { + $dp[$i] = $ft->rangeSum($li, $ri); + $ft->add($i, $dp[$i]); + } + } + + echo $dp[$n - 1] . PHP_EOL; +} + +main(); + + +// 高速化と厳密な型指定を意識しつつ、座標圧縮 + 動的計画法 + Fenwick Tree(BIT) を用いて、制約(最大 15 万件)に対応しています。 + +// ✅ 解法方針(再掲) +// ジャンプ可能地点:0, 全ての足場 X[i], ゴール地点 W +// 到達可能な方法数:dp[i](positions[i] に到達する方法の数) +// 区間加算高速化:Fenwick Tree(BIT)で dp[li..ri] を合計 +// 各 dp[i] を高速に更新して最終地点の dp を出力 + +// 📌 型指定まとめ +// 変数・関数 型 用途 +// $dp array 各位置の到達通り数 +// FenwickTree::add() (int, int): void 指定位置に加算 +// FenwickTree::sum() (int): int 前からの累積和 +// FenwickTree::rangeSum() (int, int): int 区間和(高速) +// lowerBound() (array, int): int 二分探索:最初に x 以上の位置 +// upperBound() (array, int): int 二分探索:最初に x より大きい位置 \ No newline at end of file diff --git a/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/A76.py b/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/A76.py new file mode 100644 index 00000000..48d0baeb --- /dev/null +++ b/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/A76.py @@ -0,0 +1,103 @@ +from typing import List +import bisect +import sys + +sys.setrecursionlimit(1 << 25) + +MOD: int = 10**9 + 7 + + +class FenwickTree: + def __init__(self, size: int) -> None: + self.n: int = size + self.tree: List[int] = [0] * (size + 2) + + def add(self, i: int, x: int) -> None: + """i番目にxを加算(1-indexed)""" + i += 1 + while i <= self.n + 1: + self.tree[i] = (self.tree[i] + x) % MOD + i += i & -i + + def sum(self, i: int) -> int: + """[0, i] の総和""" + i += 1 + res: int = 0 + while i > 0: + res = (res + self.tree[i]) % MOD + i -= i & -i + return res + + def range_sum(self, l: int, r: int) -> int: + """[l, r] の総和""" + return (self.sum(r) - self.sum(l - 1)) % MOD + + +def solve() -> None: + import sys + input = sys.stdin.read + data: List[str] = input().split() + + W: int = int(data[1]) + L: int = int(data[2]) + R: int = int(data[3]) + X: List[int] = list(map(int, data[4:])) + + # 全ての到達可能な位置をリストアップ + positions: List[int] = [0] + sorted(X) + [W] + size: int = len(positions) + + dp: List[int] = [0] * size + dp[0] = 1 + + ft: FenwickTree = FenwickTree(size) + ft.add(0, 1) + + for i in range(1, size): + cur_pos: int = positions[i] + left: int = cur_pos - R + right: int = cur_pos - L + + li: int = bisect.bisect_left(positions, left) + ri: int = bisect.bisect_right(positions, right) - 1 + + if li <= ri: + dp[i] = ft.range_sum(li, ri) + ft.add(i, dp[i]) + + print(dp[-1]) + + +if __name__ == "__main__": + solve() + +# ✅ 補足:使用型の説明 +# 変数 / 関数 型 説明 +# MOD int 剰余演算用の定数 +# positions List[int] 圧縮された全てのジャンプ可能地点 +# pos_to_idx Dict[int, int] 座標からインデックスへの変換 +# dp List[int] 各位置に到達する通り数 +# FenwickTree class 区間和を高速に求める構造 +# add(i, x) (int, int) -> None i 番目の値に x を加算 +# sum(i) (int) -> int [0, i] の和 +# range_sum(l,r) (int, int) -> int [l, r] の和 + +# 🧠 計算量 +# 時間:O(N log N)(座標圧縮、BIT操作) +# 空間:O(N)(BITとDP配列) + +# ✅ 補足:使用型の説明 +# 変数 / 関数 型 説明 +# MOD int 剰余演算用の定数 +# positions List[int] 圧縮された全てのジャンプ可能地点 +# pos_to_idx Dict[int, int] 座標からインデックスへの変換 +# dp List[int] 各位置に到達する通り数 +# FenwickTree class 区間和を高速に求める構造 +# add(i, x) (int, int) -> None i 番目の値に x を加算 +# sum(i) (int) -> int [0, i] の和 +# range_sum(l,r) (int, int) -> int [l, r] の和 + +# 🧠 計算量 +# 時間:O(N log N)(座標圧縮、BIT操作) +# 空間:O(N)(BITとDP配列) + diff --git a/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/A76.ts b/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/A76.ts new file mode 100644 index 00000000..685f1301 --- /dev/null +++ b/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/A76.ts @@ -0,0 +1,105 @@ +import * as fs from 'fs'; + +const MOD = 1_000_000_007; + +class FenwickTree { + private n: number; + private tree: number[]; + + constructor(n: number) { + this.n = n; + this.tree = new Array(n + 2).fill(0); + } + + add(i: number, x: number): void { + i++; + while (i <= this.n + 1) { + this.tree[i] = (this.tree[i] + x) % MOD; + i += i & -i; + } + } + + sum(i: number): number { + i++; + let res = 0; + while (i > 0) { + res = (res + this.tree[i]) % MOD; + i -= i & -i; + } + return res; + } + + rangeSum(l: number, r: number): number { + return (this.sum(r) - this.sum(l - 1) + MOD) % MOD; + } +} + +function lowerBound(arr: number[], x: number): number { + let left = 0, + right = arr.length; + while (left < right) { + const mid = (left + right) >> 1; + if (arr[mid] < x) left = mid + 1; + else right = mid; + } + return left; +} + +function upperBound(arr: number[], x: number): number { + let left = 0, + right = arr.length; + while (left < right) { + const mid = (left + right) >> 1; + if (arr[mid] <= x) left = mid + 1; + else right = mid; + } + return left; +} + +// Main function +function main(): void { + const input = fs.readFileSync('/dev/stdin', 'utf8'); + const lines = input.trim().split('\n'); + + const [N, W, L, R] = lines[0].split(' ').map(Number); + const X = lines[1].split(' ').map(Number); + + // 全地点(0, 足場, W)を座標圧縮用にソート + const positions = [0, ...X, W]; + positions.sort((a, b) => a - b); + + const posToIndex = new Map(); + positions.forEach((v, i) => posToIndex.set(v, i)); + + const n = positions.length; + const dp = new Array(n).fill(0); + dp[0] = 1; + + const ft = new FenwickTree(n); + ft.add(0, 1); + + for (let i = 1; i < n; i++) { + const cur = positions[i]; + const left = cur - R; + const right = cur - L; + + const li = lowerBound(positions, left); + const ri = upperBound(positions, right) - 1; + + if (li <= ri) { + const val = ft.rangeSum(li, ri); + dp[i] = val; + ft.add(i, val); + } + } + + console.log(dp[n - 1]); +} + +main(); + +// 📌 解法ポイント +// 座標圧縮:Wが大きすぎる(最大10⁹)ので使う点だけに圧縮 +// DP + BIT:dp[i] = Σ dp[j], 条件:L ≤ pos[i] - pos[j] ≤ R → これを BIT で高速集計 +// 計算量:O(N log N) で N ≤ 150,000 に対応 + diff --git a/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/README.md b/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/README.md new file mode 100644 index 00000000..7b4543fb --- /dev/null +++ b/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/README.md @@ -0,0 +1,129 @@ + +--- + +## 🧭 問題の要点(図解) + +``` +川幅: 65m、ジャンプ距離: [7, 37] + +足場: 5 15 30 50 55 +位置: |---|----|----|----|----| + ↑ ↑ ↑ ↑ ↑ +スタート(0m) ゴール(65m) +``` + +* 太郎君は **スタート地点 (0m)** から、**ジャンプ距離が \[7m, 37m]** で足場やゴールにジャンプ。 +* **どのような順番でジャンプしてゴールに到達できるか** の**総数を求める問題**。 + +--- + +## ✅ ステップ 1:座標圧縮と前処理 + +```ts +const positions = [0, ...X, W]; // [0, 5, 15, 30, 50, 55, 65] +positions.sort((a, b) => a - b); +``` + +📘 **図1:位置リスト(圧縮対象)** + +``` +Index: 0 1 2 3 4 5 6 +Position: 0 5 15 30 50 55 65 +``` + +* 実際にジャンプで到達する可能性のある地点のみを考慮(最大 N+2 個) +* `dp[i]` は `positions[i]` に到達する方法の数を表す + +--- + +## ✅ ステップ 2:初期化 + +```ts +dp[0] = 1; // スタート地点 0 にいる方法は1通り +ft.add(0, 1); // BITにもセット +``` + +📘 **図2:初期状態** + +``` +dp: [1, 0, 0, 0, 0, 0, 0] +position: [0, 5, 15, 30, 50, 55, 65] +``` + +--- + +## ✅ ステップ 3:各位置 i にジャンプ可能な過去の範囲を探す(二分探索) + +```ts +const left = cur - R; +const right = cur - L; + +const li = lowerBound(positions, left); +const ri = upperBound(positions, right) - 1; +``` + +📘 **図3:ジャンプ可能範囲を図示(例: i = 2, pos = 15)** + +``` +今の位置: 15 +ジャンプ元候補: 15 - 37 = -22 〜 15 - 7 = 8 + +→ 到達できる前の点: [0, 5] → positions[0], positions[1] +``` + +つまり: + +```ts +li = lowerBound(positions, -22) = 0 +ri = upperBound(positions, 8) - 1 = 1 +``` + +* `dp[2] = dp[0] + dp[1]` を求める(`BIT.rangeSum(li, ri)`) + +--- + +## ✅ ステップ 4:BIT(Fenwick Tree)による高速区間和の計算 + +📘 **図4:BITで dp\[0]+dp\[1] を合計し、dp\[2] に代入** + +```ts +dp[i] = ft.rangeSum(li, ri); +ft.add(i, dp[i]); +``` + +BIT は `O(log N)` で次のように動作: + +* `add(i, x)`:`i` 番目の値に `x` を加える +* `rangeSum(l, r)`:`dp[l] + dp[l+1] + ... + dp[r]` を計算 + +--- + +## ✅ ステップ 5:最終結果 + +```ts +console.log(dp[n - 1]); // 最後の位置 (W=65m) に到達する通り数 +``` + +📘 **図5:dp配列(最終的な通り数)** + +``` +Index: 0 1 2 3 4 5 6 +Position: 0 5 15 30 50 55 65 +dp: 1 0 1 2 2 1 7 +``` + +* `dp[6] = 7` → ゴール (65m) にたどり着く通り数は **7通り** + +--- + +## 💡 まとめ + +| 処理ステップ | 説明 | +| ----------------- | ------------------------------- | +| 座標圧縮 | 0, 足場, ゴールだけをインデックスに変換 | +| dp 初期化 | `dp[0] = 1`(スタート) | +| 各位置ごとに探索 | `pos[i]` にジャンプできる前の範囲を2分探索 | +| Fenwick Tree(BIT) | 区間和を O(log N) で計算して `dp[i]` に加算 | +| 最終出力 | `dp[ゴールのインデックス]` が答え | + +--- diff --git a/DataStructures/Trees/Heap/Deadline b/DataStructures/Trees/Heap/Deadline deleted file mode 100644 index 3bbe8d2d..00000000 --- a/DataStructures/Trees/Heap/Deadline +++ /dev/null @@ -1,19 +0,0 @@ -import sys -from typing import List, Tuple - -def main() -> None: - input_data = sys.stdin.read().strip().splitlines() - n: int = int(input_data[0]) - problems: List[Tuple[int, int]] = [] - - for line in input_data[1:]: - parts = line.split() - if len(parts) == 2: - problems.append((int(parts[0]), int(parts[1]))) - else: - raise ValueError("Each line must contain exactly two integers") - - print(solve(n, problems)) - -if __name__ == "__main__": - main() \ No newline at end of file From 04435fb148ac185ac151972f54db012d7e8225fb Mon Sep 17 00:00:00 2001 From: myoshizumi Date: Tue, 1 Jul 2025 19:04:00 +0900 Subject: [PATCH 2/2] leetcode 7. Reverse Integer --- .../leetcode/7. Reverse Integer/README.md | 115 ++++++++++++++++++ .../7. Reverse Integer/ReverseInteger.ts | 40 ++++++ .../FenwickTree/atcoder/A76/README.md | 8 ++ 3 files changed, 163 insertions(+) create mode 100644 Algorithm/Other/leetcode/7. Reverse Integer/README.md create mode 100644 Algorithm/Other/leetcode/7. Reverse Integer/ReverseInteger.ts diff --git a/Algorithm/Other/leetcode/7. Reverse Integer/README.md b/Algorithm/Other/leetcode/7. Reverse Integer/README.md new file mode 100644 index 00000000..a00b8b97 --- /dev/null +++ b/Algorithm/Other/leetcode/7. Reverse Integer/README.md @@ -0,0 +1,115 @@ +この解法は、64ビット整数を使わずに、32ビット整数の範囲を超えないかを都度チェックしながら桁を逆にしていきます。 + +--- + +### ✅ TypeScriptコード(`fs`での入力読み取り対応) + +```ts +import * as fs from 'fs'; + +const input = fs.readFileSync('/dev/stdin', 'utf8').trim(); +const x = parseInt(input); + +/** + * 32ビット整数の範囲 + */ +const INT_MIN = -(2 ** 31); +const INT_MAX = 2 ** 31 - 1; + +function reverse(x: number): number { + let result = 0; + let num = x; + + while (num !== 0) { + const digit = num % 10 | 0; // 小数点対策で |0 して整数化 + num = (num / 10) | 0; + + // resultが次の桁を追加したときにオーバーフローしないか確認 + if ( + result > Math.floor(INT_MAX / 10) || + (result === Math.floor(INT_MAX / 10) && digit > 7) + ) { + return 0; + } + if ( + result < Math.ceil(INT_MIN / 10) || + (result === Math.ceil(INT_MIN / 10) && digit < -8) + ) { + return 0; + } + + result = result * 10 + digit; + } + + return result; +} + +console.log(reverse(x)); +``` + +--- + +### 🔍 処理概要(図付きで説明) + +たとえば `x = -123` のとき: + +``` +初期状態: result = 0, num = -123 + +ループ1: + digit = -123 % 10 = -3 + num = -123 / 10 = -12 + result = 0 * 10 + (-3) = -3 + +ループ2: + digit = -12 % 10 = -2 + num = -12 / 10 = -1 + result = -3 * 10 + (-2) = -32 + +ループ3: + digit = -1 % 10 = -1 + num = -1 / 10 = 0 + result = -32 * 10 + (-1) = -321 + +終了(num === 0)→ return -321 +``` + +--- + +### 🛑 オーバーフローの例 + +例:`x = 1534236469` + +``` +途中で result = 964632435 になり、 +次の桁(9)を追加すると 9646324350 + 9 = 9646324359 > INT_MAX +→ return 0 +``` + +--- + +### ✅ テストケース例 + +```plaintext +Input: +123 +Output: +321 + +Input: +-123 +Output: +-321 + +Input: +120 +Output: +21 + +Input: +1534236469 +Output: +0 +``` + +--- diff --git a/Algorithm/Other/leetcode/7. Reverse Integer/ReverseInteger.ts b/Algorithm/Other/leetcode/7. Reverse Integer/ReverseInteger.ts new file mode 100644 index 00000000..470e7c9f --- /dev/null +++ b/Algorithm/Other/leetcode/7. Reverse Integer/ReverseInteger.ts @@ -0,0 +1,40 @@ +import * as fs from 'fs'; + +const input = fs.readFileSync('/dev/stdin', 'utf8').trim(); +const x = parseInt(input); + +/** + * 32ビット整数の範囲 + */ +const INT_MIN = -(2 ** 31); +const INT_MAX = 2 ** 31 - 1; + +function reverse(x: number): number { + let result = 0; + let num = x; + + while (num !== 0) { + const digit = num % 10 | 0; // 小数点対策で |0 して整数化 + num = (num / 10) | 0; + + // resultが次の桁を追加したときにオーバーフローしないか確認 + if ( + result > Math.floor(INT_MAX / 10) || + (result === Math.floor(INT_MAX / 10) && digit > 7) + ) { + return 0; + } + if ( + result < Math.ceil(INT_MIN / 10) || + (result === Math.ceil(INT_MIN / 10) && digit < -8) + ) { + return 0; + } + + result = result * 10 + digit; + } + + return result; +} + +console.log(reverse(x)); diff --git a/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/README.md b/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/README.md index 7b4543fb..ae226998 100644 --- a/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/README.md +++ b/DataStructures/Trees/BinaryIndexedTree/FenwickTree/atcoder/A76/README.md @@ -127,3 +127,11 @@ dp: 1 0 1 2 2 1 7 | 最終出力 | `dp[ゴールのインデックス]` が答え | --- + +| [提出日時](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-01 18:36:39 | [A76 - River Crossing](https://atcoder.jp/contests/tessoku-book/tasks/tessoku_book_bx) | [myoshizumi](https://atcoder.jp/users/myoshizumi) | [PHP (php 8.2.8)](https://atcoder.jp/contests/tessoku-book/submissions/me?f.Language=5016) | 1000 | 2451 Byte | | 248 ms | 46648 KiB | [詳細](https://atcoder.jp/contests/tessoku-book/submissions/67219001) | +| 2025-07-01 18:33:18 | [A76 - River Crossing](https://atcoder.jp/contests/tessoku-book/tasks/tessoku_book_bx) | [myoshizumi](https://atcoder.jp/users/myoshizumi) | [Go (go 1.20.6)](https://atcoder.jp/contests/tessoku-book/submissions/me?f.Language=5002) | 1000 | 1925 Byte | | 56 ms | 15992 KiB | [詳細](https://atcoder.jp/contests/tessoku-book/submissions/67218947) | +| 2025-07-01 18:27:47 | [A76 - River Crossing](https://atcoder.jp/contests/tessoku-book/tasks/tessoku_book_bx) | [myoshizumi](https://atcoder.jp/users/myoshizumi) | [Python (CPython 3.11.4)](https://atcoder.jp/contests/tessoku-book/submissions/me?f.Language=5055) | 1000 | 1741 Byte | | 473 ms | 39756 KiB | [詳細](https://atcoder.jp/contests/tessoku-book/submissions/67218847) | +| 2025-07-01 18:16:16 | [A76 - River Crossing](https://atcoder.jp/contests/tessoku-book/tasks/tessoku_book_bx) | [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 | 2371 Byte | | 150 ms | 86184 KiB | [詳細](https://atcoder.jp/contests/tessoku-book/submissions/67218646) | +| 2025-07-01 18:14:02 | [A76 - River Crossing](https://atcoder.jp/contests/tessoku-book/tasks/tessoku_book_bx) | [myoshizumi](https://atcoder.jp/users/myoshizumi) | [JavaScript (Node.js 18.16.1)](https://atcoder.jp/contests/tessoku-book/submissions/me?f.Language=5009) | 1000 | 2694 Byte | | 183 ms | 88068 KiB | [詳細](https://atcoder.jp/contests/tessoku-book/submissions/67218589) | \ No newline at end of file