公式

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

Claude 4.6 Opus (Thinking)

Overview

This problem involves managing cards using a stack (last-in, first-out) structure, computing the XOR value of the entire pile at each check operation, and finding the number of the most recent previous check operation that yielded the same XOR value.

Analysis

Key Insight: Cumulative XOR Management

A naive approach would require computing the XOR of all cards in the stack for every LOOK operation, which would take \(O(\text{stack size})\) each time, resulting in \(O(N^2)\) in the worst case.

However, XOR has the following convenient properties:

  • On addition: When a new card \(c\) is placed, the total XOR can be updated as xor_val ^ c
  • On removal: When the top card \(c\) is removed, by the XOR property (\(a \oplus a = 0\)), the value reverts with xor_val ^ c

In other words, by maintaining a single variable xor_val, we can keep the current XOR value updated in \(O(1)\) for each PUT/REMOVE operation.

Fast Lookup of “Most Recent LOOK with the Same XOR Value”

For the XOR value \(v_i\) obtained at each LOOK operation, we need to find the largest \(j\) such that \(v_j = v_i\) and \(j < i\).

This is straightforward using a dictionary (hash map). By recording the XOR value as the key and the LOOK number where that value last appeared as the value, we can find the answer in \(O(1)\) for each LOOK operation.

Let’s verify with a concrete example:

Operation xor_val LOOK number Dictionary state Output
PUT 3 3 - {} -
PUT 5 3⊕5=6 - {} -
LOOK 6 1 {6:1} -1
REMOVE 6⊕5=3 - {6:1} -
PUT 5 3⊕5=6 - {6:1} -
LOOK 6 2 {6:2} 1

At the 2nd LOOK, the XOR value is 6, and the dictionary contains {6:1}, so the answer is 1. Afterward, the dictionary is updated to {6:2}.

Algorithm

  1. Prepare a variable xor_val = 0 and an empty stack stack
  2. Prepare a dictionary last_seen (XOR value → the LOOK number where that value last appeared)
  3. For each operation:
    • PUT c: Push \(c\) onto the stack and update xor_val ^= c
    • REMOVE: Pop the top of the stack and update xor_val ^= (popped value)
    • LOOK:
      • Increment the LOOK counter by 1
      • If xor_val exists in last_seen, output that number. Otherwise, output \(-1\)
      • Update last_seen[xor_val] with the current LOOK number

Complexity

  • Time complexity: \(O(N)\) — Each operation is processed in \(O(1)\), and there are \(N\) operations in total
  • Space complexity: \(O(N)\) — The stack and dictionary each store at most \(O(N)\) elements

Implementation Notes

  • Due to the XOR property \(a \oplus a = 0\), XORing the same value twice cancels it out. This allows us to correctly update during REMOVE by simply computing xor_val ^= top

  • The last_seen dictionary is overwritten at each LOOK (since we need to find the largest \(j\), we only need to keep the most recent number)

  • Since the input can be very large, use sys.stdin.readline for fast input reading

    Source Code

import sys
input = sys.stdin.readline

def main():
    N = int(input())
    stack = []
    xor_val = 0  # current XOR of all cards in the stack
    # For each LOOK, we need the XOR value, then find the last previous LOOK with same value
    # We'll use a dictionary mapping xor_value -> last LOOK index (1-based among LOOKs)
    last_seen = {}  # xor_value -> last LOOK index
    results = []
    look_count = 0
    
    for _ in range(N):
        line = input().strip()
        if line.startswith("PUT"):
            c = int(line.split()[1])
            stack.append(c)
            xor_val ^= c
        elif line == "REMOVE":
            top = stack.pop()
            xor_val ^= top
        else:  # LOOK
            look_count += 1
            v = xor_val
            if v in last_seen:
                results.append(str(last_seen[v]))
            else:
                results.append("-1")
            last_seen[v] = look_count
    
    sys.stdout.write("\n".join(results) + "\n")

main()

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