Official

C - カードの重ね置き / Stacking Cards Editorial by admin

DeepSeek V3

Overview

This problem requires simulating card addition, removal, and inspection operations on a stack, and for each inspection operation, finding the most recent previous inspection operation that yielded the same XOR value.

Analysis

A naive approach of computing the XOR of the entire card stack for each operation would require scanning all cards for every inspection operation, resulting in \(O(N^2)\) time in the worst case, which would TLE under the constraint \(N \leq 2 \times 10^5\).

The key observation is that card operations follow a stack structure (LIFO). The addition operation (PUT) pushes a card onto the stack, and the removal operation (REMOVE) takes off the top card. Due to this property, the current XOR value can be easily computed from the previous XOR value and the new card’s value (on addition: current_xor ^ c; on removal: current_xor ^ removed_card).

Additionally, by recording the XOR value obtained at each inspection operation and managing the most recent occurrence position using a dictionary, we can efficiently search for past inspection operations with the same value.

Algorithm

  1. Initialize the current XOR value current_xor to 0
  2. Process each operation in order:
    • PUT c: Apply XOR with c to current_xor
    • REMOVE: Apply XOR with the value of the removed card (top of stack) to current_xor
    • LOOK: Record the current current_xor, and look up the most recent occurrence position in the dictionary. If found, add that number to the results; otherwise, add -1. Update the dictionary entry for that value with the current inspection operation number
  3. Output all inspection operation results

The stack itself is used to hold card values, but the XOR value calculation uses incremental updates without scanning the entire stack.

Complexity

  • Time complexity: \(O(N)\)
    • Each operation can be processed in constant time (dictionary operations are \(O(1)\) on average)
  • Space complexity: \(O(N)\)
    • The sizes of the stack and dictionary are proportional to at most \(N\)

Implementation Notes

  • Leveraging XOR properties: XORing the same value twice results in 0 (allowing removal operations to cancel out values)

  • The dictionary xor_to_last_index manages the most recent occurrence position of each XOR value

  • The inspection operation number is tracked with look_count

  • Results are stored as tuples and output all at once at the end

    Source Code

import sys

def main():
    data = sys.stdin.read().splitlines()
    n = int(data[0])
    events = data[1:1+n]
    
    stack = []
    xor_stack = []
    current_xor = 0
    results = []
    xor_to_last_index = {}
    
    look_count = 0
    
    for event in events:
        parts = event.split()
        if parts[0] == 'PUT':
            c = int(parts[1])
            stack.append(c)
            current_xor ^= c
            xor_stack.append(current_xor)
        elif parts[0] == 'REMOVE':
            removed = stack.pop()
            current_xor ^= removed
            xor_stack.append(current_xor)
        elif parts[0] == 'LOOK':
            look_count += 1
            v = current_xor
            if v in xor_to_last_index:
                results.append((look_count, xor_to_last_index[v]))
            else:
                results.append((look_count, -1))
            xor_to_last_index[v] = look_count
    
    for idx, val in results:
        print(val)

if __name__ == "__main__":
    main()

This editorial was generated by deepseekv3.

posted:
last update: