公式

A - スタンプラリー / Stamp Rally 解説 by admin 印刷ページ

Claude 4.6 Opus (Thinking)

Overview

This is a problem where you stamp an \(R \times C\) stamp \(N\) times onto an \(H \times W\) sheet, and you need to determine the final state of the sheet. If the stamp extends beyond the sheet, only the portion within the sheet is imprinted.

Analysis

Problem Breakdown

The sheet initially consists entirely of ., and the # portions of the stamp are transferred onto the sheet. Even if the same cell is stamped multiple times, it remains #, so for each cell, only “whether # was ever stamped on it” matters.

Naive Approach

The most straightforward method is to scan all \(R \times C\) cells of the stamp for each stamp press and transfer the # cells onto the sheet. In the worst case, this requires \(N \times R \times C = 1000 \times 100 \times 100 = 10^7\) operations, which is sufficiently fast.

Key Observations

  • By pre-enumerating only the positions of # in the stamp, we can skip . cells and avoid unnecessary processing.
  • Since the stamp position may extend beyond the sheet, we need to check whether each # cell falls within the bounds of the sheet.
  • Coordinates are given in 1-indexed form, and values can be 0 or less, or greater than \(H\) or \(W\), so coordinate conversion and bounds checking must be done correctly.

Algorithm

  1. Stamp Preprocessing: Store all relative coordinates \((sr, sc)\) of cells that are # in the stamp into a list.

  2. Processing Each Stamp Press: For the \(j\)-th stamp press, the top-left corner of the stamp is placed at \((r_j, c_j)\) (1-indexed) on the sheet. Convert to 0-indexed: \((r_0, c_0) = (r_j - 1, c_j - 1)\).

  3. Computing the Valid Range: Calculate the range that fits within the sheet for both row and column directions of the stamp.

    • Rows: \(sr\_start = \max(0, -r_0)\), \(sr\_end = \min(R, H - r_0)\)
    • Columns: \(sc\_start = \max(0, -c_0)\), \(sc\_end = \min(C, W - c_0)\)
  4. Imprinting: For each # position \((sr, sc)\) obtained during preprocessing, if it falls within the valid range, change cell \((r_0 + sr, c_0 + sc)\) on the sheet to #.

  5. Output: Print the sheet row by row after all stamp presses are complete.

Concrete Example

For example, suppose the sheet is \(5 \times 5\) and the stamp is the following \(2 \times 2\):

#.
.#

The # positions of the stamp are \((0,0)\) and \((1,1)\). If the top-left corner is aligned to \((2, 3)\) (1-indexed), that converts to \((1, 2)\) in 0-indexed, so cells \((1, 2)\) and \((2, 3)\) on the sheet become #.

Complexity

  • Time complexity: \(O(N \times K)\) (where \(K\) is the number of # cells in the stamp, at most \(R \times C = 10^4\))
    • Worst case \(O(N \times R \times C) = O(10^7)\), which is sufficiently fast
  • Space complexity: \(O(H \times W + R \times C)\) (for storing the sheet and the stamp)

Implementation Notes

  • Using bytearray: By managing the sheet as a bytearray, access is faster than with a 2D array. paper[pr * W + pc] = 35 directly writes '#' (ASCII code 35).

  • 1-indexed → 0-indexed conversion: Since input coordinates are 1-indexed, they must be converted as r0 = rj - 1, c0 = cj - 1.

  • Out-of-bounds checking: Even when the stamp position is far outside the sheet (i.e., the valid range is empty), there is a fallback that checks bounds individually (the if sr_start >= sr_end or sc_start >= sc_end branch in the code).

  • Fast input: By reading all input at once with sys.stdin.buffer.read() and splitting into tokens with split(), I/O is optimized.

    Source Code

import sys

def main():
    input_data = sys.stdin.buffer.read().decode()
    tokens = input_data.split()
    idx = 0
    
    H = int(tokens[idx]); idx += 1
    W = int(tokens[idx]); idx += 1
    R = int(tokens[idx]); idx += 1
    C = int(tokens[idx]); idx += 1
    
    stamp = []
    for i in range(R):
        stamp.append(tokens[idx]); idx += 1
    
    N = int(tokens[idx]); idx += 1
    
    # Use a flat array for the paper
    paper = bytearray(b'.' * (H * W))
    
    # Precompute stamp '#' positions
    stamp_positions = []
    for sr in range(R):
        for sc in range(C):
            if stamp[sr][sc] == '#':
                stamp_positions.append((sr, sc))
    
    for _ in range(N):
        rj = int(tokens[idx]); idx += 1
        cj = int(tokens[idx]); idx += 1
        
        # rj, cj are 1-indexed positions for the top-left of the stamp
        # Convert to 0-indexed
        r0 = rj - 1
        c0 = cj - 1
        
        # Determine the valid range of stamp rows/cols that fall within the paper
        sr_start = max(0, -r0)
        sr_end = min(R, H - r0)
        sc_start = max(0, -c0)
        sc_end = min(C, W - c0)
        
        if sr_start >= sr_end or sc_start >= sc_end:
            # Check if any stamp_positions fall in range
            for sr, sc in stamp_positions:
                pr = r0 + sr
                pc = c0 + sc
                if 0 <= pr < H and 0 <= pc < W:
                    paper[pr * W + pc] = 35  # '#'
            continue
        
        for sr, sc in stamp_positions:
            if sr_start <= sr < sr_end and sc_start <= sc < sc_end:
                paper[(r0 + sr) * W + (c0 + sc)] = 35  # '#'
    
    # Build output
    out = []
    for i in range(H):
        out.append(paper[i * W:(i + 1) * W].decode())
    sys.stdout.write('\n'.join(out) + '\n')

main()

This editorial was generated by claude4.6opus-thinking.

投稿日時:
最終更新: