公式

D - ビーズ列 / Bead Sequence 解説 by admin

gpt-5.5-xhigh

Overview

This problem asks you to find the shortest distance from \(S\) to \(T\) on a graph where states are A/B strings of length \(N\), and transitions are defined by 3 types of operations.
Since all operations have a cost of \(1\), we find the minimum number of operations using breadth-first search (BFS).

Analysis

Since operations can be performed any number of times, if we simply try to “enumerate all possibilities up to a certain number of steps,” we may revisit the same state multiple times, potentially causing the search to continue indefinitely.

However, since bead sequences are A/B strings of length \(N\), the number of possible states is at most

\(2^N\)

Given the constraint \(N \leq 25\), we can treat all states as vertices in a graph.

The operations available from each state are as follows:

  • Rotate left
  • Rotate right
  • For each positive divisor \(d\) of \(N\) (\(d < N\)), repeat the first \(d\) characters

Since all operations have cost \(1\), using BFS guarantees that the distance when we first reach \(T\) is the minimum number of operations.

Additionally, handling strings directly would cost \(O(N)\) for rotations and comparisons.
Instead, we encode A as 0 and B as 1, representing strings as integer bit sequences.

For example, the string ABBA can be represented as follows:

  • A \(\rightarrow 0\)
  • B \(\rightarrow 1\)

By storing each character as a bit, we can efficiently perform rotations and extraction of the first \(d\) characters using bitwise operations.

Algorithm

First, convert strings \(S, T\) to integers.

If the \(i\)-th character of the string is B, set the \(i\)-th bit of the integer to \(1\).

if (s[i] == 'B') v |= (1 << i);

This allows a string of length \(N\) to be represented as an integer between \(0\) and \(2^N - 1\).

Next, perform BFS.

For state \(x\), create the following transitions:

Left Rotation

Move the first character, i.e., bit \(0\), to the end, i.e., bit \(N-1\).

int leftRot = (x >> 1) | ((x & 1) << (N - 1));

Right Rotation

Move the last character, i.e., bit \(N-1\), to the front, i.e., bit \(0\).

int rightRot = ((x << 1) & fullMask) | (x >> (N - 1));

Here, fullMask = (1 << N) - 1 is used to clear unnecessary upper bits.

Pattern Duplication

Let \(d\) be a positive divisor of \(N\) with \(d < N\).

The first \(d\) characters of the current state \(x\) are the lower \(d\) bits.

int pattern = x & ((1 << d) - 1);

We create a string by repeating this pattern \(N/d\) times.

For example, if \(N = 6, d = 2\) and the leading pattern is AB, the result is:

ABABAB

In the code, computing this transformation every time would be slow, so we precompute it in a repeatTable.

table[p] = the state obtained by repeating p to length N

In BFS, when we reach an unvisited state, we record its distance.

dist[y] = dist[x] + 1;

If that state is the target target, we output the distance and terminate.

If BFS completes without reaching target, we output -1.

Complexity

Let \(D\) be the number of positive divisors \(d < N\) of \(N\).

The number of transitions examined from each state is \(O(D + 2)\) (left rotation, right rotation, and pattern duplication for each \(d\)).

  • Time complexity: \(O(2^N \cdot D)\)
  • Space complexity: \(O(2^N)\)

Implementation Notes

  • Representing strings as integer bit sequences allows fast state comparison and rotation.

  • In BFS, dist[state] == -1 is used to indicate an unvisited state.

  • Precomputing pattern duplication for each divisor \(d\) means that during BFS, we only need to look up a table.

  • If \(S = T\), output 0 immediately and terminate.

    Source Code

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N;
    string S, T;
    cin >> N >> S >> T;

    auto encode = [&](const string& s) {
        int v = 0;
        for (int i = 0; i < N; i++) {
            if (s[i] == 'B') v |= (1 << i);
        }
        return v;
    };

    int start = encode(S);
    int target = encode(T);

    if (start == target) {
        cout << 0 << '\n';
        return 0;
    }

    int total = 1 << N;
    int fullMask = total - 1;

    vector<int> prefixMasks;
    vector<vector<int>> repeatTable;

    for (int d = 1; d < N; d++) {
        if (N % d != 0) continue;

        int sz = 1 << d;
        vector<int> table(sz, 0);

        for (int p = 0; p < sz; p++) {
            int v = 0;
            for (int pos = 0; pos < N; pos += d) {
                v |= (p << pos);
            }
            table[p] = v;
        }

        prefixMasks.push_back(sz - 1);
        repeatTable.push_back(move(table));
    }

    vector<int> dist(total, -1);
    vector<int> q;
    q.reserve(total);

    dist[start] = 0;
    q.push_back(start);

    auto push_state = [&](int y, int nd) -> bool {
        if (dist[y] != -1) return false;
        dist[y] = nd;
        if (y == target) {
            cout << nd << '\n';
            return true;
        }
        q.push_back(y);
        return false;
    };

    for (size_t head = 0; head < q.size(); head++) {
        int x = q[head];
        int nd = dist[x] + 1;

        int leftRot = (x >> 1) | ((x & 1) << (N - 1));
        if (push_state(leftRot, nd)) return 0;

        int rightRot = ((x << 1) & fullMask) | (x >> (N - 1));
        if (push_state(rightRot, nd)) return 0;

        for (size_t i = 0; i < repeatTable.size(); i++) {
            int y = repeatTable[i][x & prefixMasks[i]];
            if (push_state(y, nd)) return 0;
        }
    }

    cout << -1 << '\n';
    return 0;
}

This editorial was generated by gpt-5.5-xhigh.

投稿日時:
最終更新: