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
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// 以下は Go 1.20.6 を用いた解法です。
// **制約(N ≤ 100,000)に対応するため、計算量 O(N log N)** のアルゴリズム(2次元LIS)を使用しています。
// ソートと二分探索を使った効率的な処理で、型を明示し、関数分離も行っています。

// ---

// ## ✅ Go 実装(型明示・関数分離)

// ```go
package main

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

// Box は各箱の構造体。縦と横を持つ。
type Box struct {
X int // 縦の長さ
Y int // 横の長さ
}

// maxNestingDepth は最大で何重に箱をネストできるかを求める。
// @param boxes []Box - 各箱の情報
// @return int - 最大ネスト数
func maxNestingDepth(boxes []Box) int {
// X昇順、Xが同じならY降順でソート
sort.Slice(boxes, func(i, j int) bool {
if boxes[i].X == boxes[j].X {
return boxes[i].Y > boxes[j].Y
}
return boxes[i].X < boxes[j].X
})

// Y方向のLISを求める(O(N log N))
lis := make([]int, 0, len(boxes))

for _, box := range boxes {
y := box.Y
idx := lowerBound(lis, y)
if idx == len(lis) {
lis = append(lis, y)
} else {
lis[idx] = y
}
}

return len(lis)
}

// lowerBound は slice の中で target 以上の最小のインデックスを返す。
// @param slice []int - 単調増加列
// @param target int - 探す値
// @return int - 最左位置(lower_bound)
func lowerBound(slice []int, target int) int {
left, right := 0, len(slice)
for left < right {
mid := (left + right) / 2
if slice[mid] < target {
left = mid + 1
} else {
right = mid
}
}
return left
}

// main は標準入力を読み込み、最大ネスト数を出力する。
func main() {
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
n, _ := strconv.Atoi(scanner.Text())

boxes := make([]Box, n)

for i := 0; i < n && scanner.Scan(); i++ {
line := scanner.Text()
parts := strings.Fields(line)
x, _ := strconv.Atoi(parts[0])
y, _ := strconv.Atoi(parts[1])
boxes[i] = Box{X: x, Y: y}
}

result := maxNestingDepth(boxes)
fmt.Println(result)
}

// ## ✅ 計算量とメモリ使用量

// | 項目 | 値 |
// | ------ | ---------------------------------- |
// | 時間計算量 | `O(N log N)`(ソート + LIS) |
// | 空間計算量 | `O(N)`(LIS配列+入力配列) |
// | メモリ使用量 | 約 10〜15MB(N ≒ 100,000 のとき) |
// | 最大入力対応 | `N ≦ 100,000`、`X,Y ≦ 500,000` まで対応 |

// ---

// ## ✅ 実行例

// ### 入力:

// ```
// 5
// 30 50
// 10 30
// 40 10
// 50 20
// 40 60
// ```

// ### 出力:

// ```
// 3
// ```

// ---

// ## ✅ 解法ポイント

// * `sort.Slice()` で X昇順・Y降順の安定ソート
// * `lowerBound` による Y の LIS 構築(ネスト数=LISの長さ)
// * Go のスライスを活かした効率的実装

Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// 以下は、**JavaScript (Node.js 18.16.1)** を使った解法です。
// 標準入力は `fs` モジュールを使って読み込み、\*\*箱をネストできる最大の深さ(最大チェイン長)\*\*を求めます。

// ---

// ## ✅ 解法概要(O(N log N) 解法)

// この問題は **2次元のLongest Increasing Subsequence(LIS)問題**に帰着できます。

// 1. **X昇順**、**Y降順**でソートする(Xが同じならYが逆順)

// * こうすることで、`X` も `Y` も単調増加となる部分列を求めるときに、`X` が同じで `Y` だけ違う箱が同列に並ばないようにできます。
// 2. `Y` だけを取り出し、LIS(Longest Increasing Subsequence)を求める

// ---

// ## ✅ コード実装

// ```javascript
const fs = require('fs');

/**
* 与えられた箱の配列に対して最大で何重にネストできるかを求める
* @param {number[][]} boxes - 各箱の [X, Y] の配列
* @returns {number} - 最大のネスト数
*/
function maxNestingDepth(boxes) {
// 1. X昇順、Xが同じならY降順でソート
boxes.sort((a, b) => {
if (a[0] === b[0]) return b[1] - a[1]; // Y降順
return a[0] - b[0]; // X昇順
});

// 2. Yのみを取り出して LIS を求める
const lis = []; // 単調増加部分列(パイル)

for (const [_, y] of boxes) {
// 二分探索で挿入位置を探す
let left = 0, right = lis.length;
while (left < right) {
const mid = (left + right) >> 1;
if (lis[mid] < y) left = mid + 1;
else right = mid;
}

if (left === lis.length) {
lis.push(y);
} else {
lis[left] = y;
}
}

return lis.length;
}

// 標準入力の読み取り
function main() {
const input = fs.readFileSync('/dev/stdin', 'utf8').trim().split('\n');
const N = Number(input[0]);
const boxes = input.slice(1).map(line => line.split(' ').map(Number));

const result = maxNestingDepth(boxes);
console.log(result);
}

main();
// ```

// ---

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

// * 時間計算量: **O(N log N)**(ソートとLISに二分探索)
// * 空間計算量: **O(N)**(LIS保存用)

// ---

// ## ✅ テスト例

// 入力例1:

// ```
// 5
// 30 50
// 10 30
// 40 10
// 50 20
// 40 60
// ```

// 出力:

// ```
// 3
// ```
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<!-- 以下は PHP 8.2.8 を用いた解法です。
**制約: N ≤ 100,000、各座標 ≤ 500,000** に対応できるよう、**計算量 O(N log N)**、メモリ効率にも注意しています。

---

## ✅ 解法方針(2次元LIS)

1. `X` 昇順、`Y` 降順にソート
2. `Y` のみ取り出し、\*\*LIS(最長増加部分列)\*\*を `二分探索` によって求める

---

## ✅ PHP 実装(関数分離、型付き)

```php -->
<?php

/**
* 最大ネスト数を求める関数
*
* @param array<int, array{0: int, 1: int}> $boxes - 各箱の [X, Y] を格納した配列
* @return int - 最大ネスト数
*/
function maxNestingDepth(array $boxes): int {
// ソート: X 昇順、同じなら Y 降順
usort($boxes, function ($a, $b) {
if ($a[0] === $b[0]) {
return $b[1] <=> $a[1]; // Y 降順
}
return $a[0] <=> $b[0]; // X 昇順
});

$lis = []; // 最長増加部分列 (Y方向)

foreach ($boxes as [$x, $y]) {
$pos = binarySearchLeft($lis, $y);
if ($pos === count($lis)) {
$lis[] = $y;
} else {
$lis[$pos] = $y;
}
}

return count($lis);
}

/**
* 二分探索(lower_bound)で挿入位置を探す
*
* @param array<int> $arr - 単調増加配列
* @param int $target - 挿入対象の数
* @return int - 挿入すべき位置(最左の >= target の位置)
*/
function binarySearchLeft(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;
}

/**
* メイン処理:標準入力から読み込み、最大ネスト数を出力
*/
function main(): void {
$input = file('php://stdin', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$n = (int)$input[0];

$boxes = [];
for ($i = 1; $i <= $n; $i++) {
[$x, $y] = array_map('intval', explode(' ', $input[$i]));
$boxes[] = [$x, $y];
}

$result = maxNestingDepth($boxes);
echo $result . PHP_EOL;
}

main();
// ```

// ---

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

// | 項目 | 内容 |
// | ------- | ------------------------- |
// | 時間計算量 | `O(N log N)` (ソート + LIS) |
// | 空間計算量 | `O(N)`(LIS用配列 + 入力配列) |
// | メモリ使用量例 | ≒15〜20MB(`N=100,000` の場合) |
// | 対応最大サイズ | `N ≦ 100,000` |

// ---

// ## ✅ 入力例

// ```
// 5
// 30 50
// 10 30
// 40 10
// 50 20
// 40 60
// ```

// ### 出力:

// ```
// 3
// ```

// ---

// ## ✅ 解説補足

// * `usort` による `X` 昇順、`Y` 降順ソートで誤ネストを防止
// * `binarySearchLeft` による効率的な LIS 構築
// * PHP 8.2 の型サポート(配列要素のタプル型も docblock で明示)

// ---

// ご希望があれば、ネスト順序の復元や可視化解説も可能です。
Loading