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
145 changes: 145 additions & 0 deletions Mathematics/2D prefix sum/atcoder/B08/B08.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// 以下は、問題に対する **Go (Golang)** の解法です。
// 制約(点数・クエリ最大10⁵、座標範囲1500)を踏まえ、**2次元累積和(2D prefix sum)** を使って高速にクエリ処理を行います。
// 型を明示し、**実行時間とメモリ使用量を考慮**した設計です。

// ## ✅ 解法概要(再確認)

// * 入力された点を `grid[x][y]` にカウント。
// * `prefix[x][y]` に (1,1)〜(x,y) の点数累積和を構築。
// * 各クエリで矩形 `[a,c] × [b,d]` の点数を O(1) で取得。

// ## ✅ Go 実装(型明示・最適化済)

package main

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

const SIZE = 1501

func main() {
reader := bufio.NewReaderSize(os.Stdin, 1<<20) // 1MB buffer
writer := bufio.NewWriter(os.Stdout)
defer writer.Flush()

// 数値の読み取り関数
readInt := func() int {
line, _ := reader.ReadString('\n')
val, _ := strconv.Atoi(strings.TrimSpace(line))
return val
}

readInts := func() []int {
line, _ := reader.ReadString('\n')
fields := strings.Fields(line)
res := make([]int, len(fields))
for i, s := range fields {
res[i], _ = strconv.Atoi(s)
}
return res
}

// 点の数
var N int = readInt()

// grid[x][y]: 各点のカウント
var grid [SIZE][SIZE]int

for i := 0; i < N; i++ {
p := readInts()
x, y := p[0], p[1]
grid[x][y]++
}

// 2次元累積和の構築
var prefix [SIZE][SIZE]int

for x := 1; x < SIZE; x++ {
for y := 1; y < SIZE; y++ {
prefix[x][y] = grid[x][y] +
prefix[x-1][y] +
prefix[x][y-1] -
prefix[x-1][y-1]
}
}

// クエリ数
var Q int = readInt()

for i := 0; i < Q; i++ {
p := readInts()
a, b, c, d := p[0], p[1], p[2], p[3]

count := prefix[c][d] -
prefix[a-1][d] -
prefix[c][b-1] +
prefix[a-1][b-1]

fmt.Fprintln(writer, count)
}
}

// ## ✅ 実行例

// ### 入力

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

// ### 出力

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

// ---

// ## ✅ 型と構造体の解説

// | 変数 | 型 | 説明 |
// | ------------ | ----------------- | ------------- |
// | `grid` | `[1501][1501]int` | 点の存在をカウント |
// | `prefix` | `[1501][1501]int` | 2D累積和 |
// | `readInt()` | `func() int` | 1行読み取り & 整数変換 |
// | `readInts()` | `func() []int` | 複数整数を1行で読み取り |

// ---

// ## ✅ 計算量

// | 処理内容 | 時間計算量 |
// | ------ | ------------ |
// | グリッド構築 | O(N) |
// | 累積和構築 | O(1500×1500) |
// | クエリ処理 | O(Q) |
// | **合計** | ≈ 数百万オーダー |

// → **Go の処理性能なら 5 秒以内で十分対応可能**

// ## ✅ メモリ消費量

// * `grid` + `prefix`: `1501×1501×4バイト×2 ≒ 約18MB`
// * 制限(1024MiB)の **2%以下** に収まる。

// ## ✅ 補足

// * `bufio.Reader` を使って **高速な標準入力読み取り**。
// * `fmt.Fprintln(writer, ...)` により、**高速な出力**を実現。
// * 全体を **配列ベース(\[SIZE]\[SIZE]int)で確保済み**なので、メモリの再確保もなく非常に高速。
82 changes: 82 additions & 0 deletions Mathematics/2D prefix sum/atcoder/B08/B08.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// JavaScript(Node.js)で効率的にこの問題を解く実装です。\*\*2次元累積和(2D prefix sum)\*\*を使うことで、各クエリに対して **O(1)** で解答でき、全体で高速に処理できます。

// ### ✅ 解法概要(2次元累積和)
// 1. **入力点をカウントしてグリッドにプロット**(最大1500×1500の2D配列)。
// 2. **2次元累積和テーブル(prefixSum)を構築**。
// 3. 各クエリごとに、**累積和を使って矩形領域内の点数を計算**。

// ### ✅ コード(`fs` 使用)
const fs = require('fs');

const input = fs.readFileSync('/dev/stdin', 'utf8').trim().split('\n');
let idx = 0;

// N: 点の数
const N = parseInt(input[idx++]);
const gridSize = 1501;

// グリッド初期化
const grid = Array.from({ length: gridSize }, () => new Array(gridSize).fill(0));

// 点の入力
for (let i = 0; i < N; i++) {
const [x, y] = input[idx++].split(' ').map(Number);
grid[x][y]++;
}

// 2次元累積和を作成
const prefixSum = Array.from({ length: gridSize }, () => new Array(gridSize).fill(0));

for (let x = 1; x < gridSize; x++) {
for (let y = 1; y < gridSize; y++) {
prefixSum[x][y] =
grid[x][y] +
prefixSum[x - 1][y] +
prefixSum[x][y - 1] -
prefixSum[x - 1][y - 1];
}
}

// Q: クエリ数
const Q = parseInt(input[idx++]);

// クエリ処理
const output = [];

for (let i = 0; i < Q; i++) {
const [a, b, c, d] = input[idx++].split(' ').map(Number);

const result =
prefixSum[c][d] -
prefixSum[a - 1][d] -
prefixSum[c][b - 1] +
prefixSum[a - 1][b - 1];

output.push(result);
}

// 結果出力
console.log(output.join('\n'));
// ### ✅ 実行時間とメモリ
// * **実行時間**: 入力・累積和構築: `O(N + W * H)`、クエリ処理: `O(Q)`
// * **空間使用**: `O(W * H)` = `O(1500 × 1500)` ≒ 約 9MB(安全)

// ### ✅ 入力例
// ```bash
// $ echo "5
// 1 3
// 2 5
// 3 4
// 2 6
// 3 3
// 3
// 1 3 3 6
// 1 5 2 6
// 1 3 3 5" | node main.js
// ```

// ```
// 5
// 2
// 4
// ```
136 changes: 136 additions & 0 deletions Mathematics/2D prefix sum/atcoder/B08/B08.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<!-- 以下は、指定された問題に対する **PHP による高速実装**です。
入力制約(最大 100,000 点・クエリ、座標範囲 1〜1500)を考慮し、**2次元累積和(2D prefix sum)** を使って時間・メモリを最適化しています。

---

## ✅ 解法概要(再確認)

* 点の分布を `grid[x][y]` にカウント。
* `prefix[x][y]` に左上から `(x, y)` までの点の個数の累積和を構築。
* クエリに対し、**矩形和を O(1)** で計算。
## ✅ PHP 実装(型明示 + 最適化)
<?php

function readInts(): array {
return array_map('intval', explode(' ', trim(fgets(STDIN))));
}

function main(): void {
$SIZE = 1501;

/** @var int $N */
$N = intval(trim(fgets(STDIN)));

// 初期化: 点の存在を記録する2Dグリッド
/** @var int[][] $grid */
$grid = array_fill(0, $SIZE, array_fill(0, $SIZE, 0));

for ($i = 0; $i < $N; $i++) {
[$x, $y] = readInts();
$grid[$x][$y]++;
}

// 累積和構築: prefix[x][y] は (1,1)〜(x,y) の矩形内の点数
/** @var int[][] $prefix */
$prefix = array_fill(0, $SIZE, array_fill(0, $SIZE, 0));

for ($x = 1; $x < $SIZE; $x++) {
for ($y = 1; $y < $SIZE; $y++) {
$prefix[$x][$y] = $grid[$x][$y]
+ $prefix[$x - 1][$y]
+ $prefix[$x][$y - 1]
- $prefix[$x - 1][$y - 1];
}
}

// クエリ処理
/** @var int $Q */
$Q = intval(trim(fgets(STDIN)));

$output = [];

for ($i = 0; $i < $Q; $i++) {
[$a, $b, $c, $d] = readInts();

$count = $prefix[$c][$d]
- $prefix[$a - 1][$d]
- $prefix[$c][$b - 1]
+ $prefix[$a - 1][$b - 1];

$output[] = $count;
}

echo implode("\n", $output) . "\n";
}

main();

// ## ✅ 型解説(PHP 8.2対応)

// | 変数 | 型 | 説明 |
// | --------- | --------- | ------- |
// | `$N, $Q` | `int` | 点数、クエリ数 |
// | `$grid` | `int[][]` | 点の数カウント |
// | `$prefix` | `int[][]` | 2次元累積和 |
// | `$output` | `int[]` | 各クエリの答え |

// ---

// ## ✅ 実行例(入力)

// ```bash
// $ php main.php
// ```

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

// ### 出力

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

// ---

// ## ✅ 実行時間・メモリ分析

// ### 時間計算量

// | 処理 | 時間 |
// | ------ | -------- |
// | 入力 | O(N + Q) |
// | グリッド構築 | O(N) |
// | 累積和構築 | O(1500²) |
// | クエリ処理 | O(Q) |

// → 合計 約 3百万ステップ程度。PHP でも余裕で **5秒以内**。

// ### メモリ使用量

// * `grid`, `prefix`: `1501 × 1501 × 4byte × 2 ≒ 約18MB`
// * クエリ・結果出力等を含めても **30MB未満**
// * 制限:1024 MiB 内に余裕で収まる

// ---

// ## ✅ 補足

// * `fgets(STDIN)` + `explode` を使って、**高速な入力処理**を実現。
// * 2次元累積和の使い方は Python や TypeScript と同じです。

// ---

// ご希望であれば、**PHPでも2D累積和の図解やクエリ処理の可視化**も提供できます!必要ですか?
Loading