Official

E - カードの消去ゲーム / Card Elimination Game Editorial by admin

gpt-5.5-high

Overview

The cards that remain form a subsequence of the original card sequence.
The key point is determining “when we choose the positions of the cards to keep, whether all the deleted intervals between them can be completely eliminated.”

Analysis

First, the operations do not change the order of cards; they only remove cards.
Therefore, the final \(L\) remaining cards form a subsequence selected from the original \(N\) cards.

Let the positions of the remaining cards be

\[{p_1 < p_2 < \cdots < p_L}\]

Then all cards in the following intervals must be completely eliminated:

  • \([0, p_1)\)
  • \((p_1, p_2)\)
  • \((p_2, p_3)\)
  • \(\cdots\)
  • \((p_{L-1}, p_L)\)
  • \((p_L, N)\)

Here, intervals are considered as 0-indexed half-open intervals.

Also, for the remaining cards’ string to become \(T\), we need:

\[S_{p_j} = T_j\]


Next, let’s think about the integers written on the cards.

The deletion operation removes two adjacent cards that have “the same color” and “the same written integer.”
However, integers can be freely written at the beginning.

For two cards being deleted as a pair, we just need to write the same integer on them.
Since different pairs can use the same integer, the integers on deleted cards can be freely chosen as needed.

On the other hand, for the remaining cards, we simply write the specified \(Q\) values.
Since \(Q_i\) satisfies \(1 \leq Q_i \leq M\) in the constraints, they can always be written.

Therefore, in this problem, the values of \(Q\) and \(M\) actually do not affect the judgment.
What essentially matters is “whether we can eliminate all intervals by looking at colors only.”


Now, let’s consider whether a color sequence in a given interval can be completely eliminated.

For example, if the color sequence is

ABBA

then removing the central BB makes AA adjacent, which can also be removed, so the entire sequence can be eliminated.

This can be determined using a stack.

Processing from left to right:

  • If the top of the stack has the same color, those two cards can be matched and removed, so pop
  • If it’s a different color, push

If the stack is empty at the end, the entire interval can be eliminated.

For example, with ABBA:

A push
B push
B matches top, so pop
A matches top, so pop

The stack becomes empty.

On the other hand, ABAB cannot be fully eliminated because the stack doesn’t become empty.


Naively, the number of ways to choose remaining card positions is at most \(\binom{N}{L}\), making exhaustive search infeasible.
Instead, we precompute which intervals can be eliminated and use that information for DP.

Algorithm

First, we precompute whether each interval \([l, r)\) can be eliminated.

In the code, good_from[l] is stored as a bitset.

  • Bit r of good_from[l] is set
  • This means the interval \([l, r)\) can be completely eliminated

For each \(l\), we extend the right endpoint \(r\) while performing the stack check, recording positions where the stack becomes empty.


Next, we perform DP.

Define dp[j][i] as follows:

  • We have finished selecting up to the \(j\)-th character of the target string \(T\)
  • The last selected card is at position \(i\)
  • All unnecessary cards before it can be eliminated

The initial state consists of positions where:

\[S_i = T_0\]

and the interval from the beginning to just before \(i\), i.e., \([0, i)\), can be eliminated.

For transitions, if the previous selected position is \(p\) and the next selected position is \(i\), then:

\[p < i\]

and the interval between them:

\[[p+1, i)\]

must be eliminable.

That is, the condition for:

\[dp[j][i] = true\]

is:

  • \(S_i = T_j\)
  • There exists a \(p\) such that dp[j-1][p] = true
  • The interval \([p+1, i)\) is eliminable

Finally, if the last remaining card is at position \(p\), we succeed if the interval \([p+1, N)\) can be eliminated.


In the implementation, this DP is accelerated using bitsets.

  • letter_masks[c]
    Bitset of card positions where character c is written
  • cur
    Bitset of card positions reachable in the current DP state

For transitions, for each position p in cur, we OR good_from[p+1].
This allows us to compute all candidate positions for the next selection at once.

Then, we keep only positions that match the target character T[j].

cur = nxt_candidates & letter_masks[ord(T[j]) - 97]

At the end, we check whether we can eliminate from the current position to the tail.

Complexity

  • Time complexity: \(O(N^2 + L N^2 / w)\)
    where \(w\) is the number of bits per word. Without bit operations, the naive estimate is \(O(N^3)\) in the worst case.
  • Space complexity: \(O(N^2 / w)\) words, i.e., \(O(N^2)\) bits

Since \(N \leq 1000\), this runs sufficiently fast.

Implementation Details

First, the number of deleted cards is \(N-L\).
Since each operation removes 2 cards at a time, if \(N-L\) is odd, it is absolutely impossible.

if (N - L) & 1:
    print("No")
    return

Also, although \(Q\) is given as input, it is not used for the judgment.
The remaining cards simply have \(Q\) written on them, and the integers on deleted cards can be freely adjusted.

However, the input must still be read and discarded.

_ = input().split()

By managing whether intervals \([l, r)\) can be eliminated using bits, we can efficiently process the DP transitions.

Source Code

import sys

def main():
    input = sys.stdin.readline

    N, M, L = map(int, input().split())
    S = input().strip()
    P = input().strip()
    T = input().strip()
    _ = input().split()

    if (N - L) & 1:
        print("No")
        return

    good_from = [0] * (N + 1)

    for l in range(N, -1, -1):
        stack = []
        mask = 1 << l
        for r in range(l, N):
            c = P[r]
            if stack and stack[-1] == c:
                stack.pop()
            else:
                stack.append(c)
            if not stack:
                mask |= 1 << (r + 1)
        good_from[l] = mask

    letter_masks = [0] * 26
    for i, ch in enumerate(S):
        letter_masks[ord(ch) - 97] |= 1 << i

    cur = good_from[0] & letter_masks[ord(T[0]) - 97]
    if cur == 0:
        print("No")
        return

    rows_after = [good_from[i + 1] for i in range(N)]

    for j in range(1, L):
        nxt_candidates = 0
        x = cur
        while x:
            lb = x & -x
            p = lb.bit_length() - 1
            nxt_candidates |= rows_after[p]
            x -= lb

        cur = nxt_candidates & letter_masks[ord(T[j]) - 97]
        if cur == 0:
            print("No")
            return

    end_mask = 0
    bitN = 1 << N
    for p in range(N):
        if rows_after[p] & bitN:
            end_mask |= 1 << p

    print("Yes" if (cur & end_mask) else "No")

if __name__ == "__main__":
    main()

This editorial was generated by gpt-5.5-high.