公式

B - ランプ列の分割スコア最大化 / Maximizing the Partition Score of a Lamp Sequence 解説 by admin

Gemini 3.0 Flash (Thinking)

Overview

After performing bit shift operations on Takahashi’s lamp sequence \(X\) up to \(K\) times based on certain conditions, we split a total of \(M+1\) sequences (combining with \(M\) lamp sequences \(Y_j\)) at a common position \(p\). When summing the left and right values across all sequences, the goal is to maximize the total sum \(A+B\).

Analysis

1. Simulating Takahashi’s Operations

Takahashi’s operation is: “as long as the leftmost bit is \(0\), remove it and append \(1\) to the right end.” In terms of bit representation, this works as follows: - If the leftmost bit (least significant bit) is \(0\), shift the entire value right by \(1\) bit and set the most significant bit (the \(2^{N-1}\) position) to \(1\). - Repeat this operation until either “\(K\) operations have been performed” or “the least significant bit becomes \(1\).”

In other words, if we let \(z\) be the number of consecutive \(0\)s in the lower bits of the initial state \(X\), the actual number of operations \(k\) is \(\min(K, z)\). After the operations, \(X\) becomes the original value right-shifted by \(k\) bits, with the vacated upper \(k\) bits all filled with \(1\)s.

2. Organizing the Score Calculation Formula

For a split position \(p\) (\(1 \le p \le N-1\)), the score of a lamp sequence \(S\) is the sum of: - Integer value of the left part: The value represented by the lower \(p\) bits of \(S\). - Integer value of the right part: The upper \(N-p\) bits of \(S\), re-indexed starting from \(2^0\) (i.e., the value after right-shifting by \(p\) bits).

For all \(M+1\) lamp sequences, let \(count[i]\) be the total number of \(1\)s at each bit position \(i\) (\(0 \le i < N\)). Then the total left sum \(A\) and right sum \(B\) across all lamp sequences can be expressed as: $\(A = \sum_{i=0}^{p-1} count[i] \cdot 2^i\)\( \)\(B = \sum_{i=p}^{N-1} count[i] \cdot 2^{i-p}\)$

3. Efficient Search for the Maximum

The split position \(p\) ranges from \(1\) to \(N-1\). Naively computing \(A\) and \(B\) for each \(p\) would take \(O(N^2)\), but using a cumulative sum approach, we can compute them in \(O(N)\): - \(A\) can be updated by adding \(count[p-1] \cdot 2^{p-1}\) each time \(p\) is incremented. - \(B\) can be computed in the decreasing direction of \(p\) using the recurrence \(B(p) = count[p] + 2 \cdot B(p+1)\).

Algorithm

  1. Bit Counting: For the \(M\) sequences \(Y_j\), record the number of \(1\)s at each bit position in the array count.
  2. Applying the Operation: Count the number of consecutive \(0\)s \(z\) from the lower bits of \(X\), and compute the number of operations \(k = \min(K, z)\). Update \(X\) to its state after \(k\) operations, and add its bits to count.
  3. Score Calculation:
    • For \(p = 1, \dots, N-1\), precompute the left sum \(A[p]\).
    • For \(p = N-1, \dots, 1\), compute the right sum \(B[p]\) from the back.
  4. Obtaining the Maximum: Output the maximum value of \(A[p] + B[p]\) over all \(p\).

Complexity

  • Time Complexity: \(O(MN)\)
    • Scanning the bits of \(M\) sequences \(Y_j\) takes \(O(MN)\).
    • The subsequent search over \(p\) is \(O(N)\).
    • With \(N \le 46, M \le 2 \times 10^5\), the total number of operations is approximately \(9.2 \times 10^6\), which is sufficiently fast.
  • Space Complexity: \(O(N)\)
    • We maintain arrays count, A, B of length \(N\).

Implementation Notes

  • Handling Large Values: The answer can be as large as approximately \((M+1) \cdot 2^N\). Under the given constraints, it is guaranteed to fit in a signed 64-bit integer (long long), but care must be taken to avoid overflow during intermediate calculations. In C++, using __int128 allows for safer computation.

  • Bit Operations: When constructing the value of \(X\) after operations, we can create a mask of \(k\) consecutive \(1\)s using (1LL << k) - 1, then left-shift it by \(N-k\) bits to fill the upper bits with \(1\)s.

    Source Code

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

/**
 * Problem: Lamp sequence splitting score maximization
 * Takahashi has N lamps (0 or 1). Operation: if the leftmost is 0, shift right and add 1 at the end.
 * Max K operations. Then find a split position p (1 <= p <= N-1) for Takahashi's lamp string and
 * M additional lamp strings to maximize the sum of (left part value + right part value).
 */

int main() {
    // Faster I/O
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    long long N, K, M, X;
    if (!(cin >> N >> K >> M >> X)) return 0;

    // count[i] will store the total number of '1' bits at position i across all M+1 lamp strings.
    vector<long long> count(N, 0);

    // Read M additional lamp strings
    for (int i = 0; i < M; ++i) {
        long long Y;
        cin >> Y;
        for (int j = 0; j < N; ++j) {
            if ((Y >> j) & 1) {
                count[j]++;
            }
        }
    }

    // Determine the number of operations performed on Takahashi's lamp string X.
    // The operation shifts X right and adds a 1 at the (N-1)-th bit as long as the 0-th bit is 0.
    // This happens at most K times or until the 0-th bit becomes 1.
    long long z = 0;
    if (X == 0) {
        z = N;
    } else {
        long long tempX = X;
        while (z < N && (tempX & 1) == 0) {
            z++;
            tempX >>= 1;
        }
    }
    
    // Total operations k is the minimum of K and the number of leading zeros (from the right).
    long long k = min(K, z);
    if (k > 0) {
        if (k == N) {
            X = (1LL << N) - 1;
        } else {
            // After k operations, the first k bits are removed and k ones are added at the end.
            X = (X >> k) | (((1LL << k) - 1) << (N - k));
        }
    }

    // Add bits of the modified X to the count array.
    for (int j = 0; j < N; ++j) {
        if ((X >> j) & 1) {
            count[j]++;
        }
    }

    /**
     * For a split point p (1 <= p <= N-1):
     * Left part value for a string s: s & (2^p - 1)
     * Right part value for a string s: s >> p
     * Total A = sum of left parts = sum_{i=0}^{p-1} count[i] * 2^i
     * Total B = sum of right parts = sum_{i=p}^{N-1} count[i] * 2^{i-p}
     * We maximize A + B.
     */

    // Use __int128 for intermediate calculations to avoid overflow.
    // Although long long (64-bit) should be enough given the problem constraints.
    vector<__int128> A(N + 1, 0);
    vector<__int128> B(N + 1, 0);

    __int128 pow2 = 1;
    for (int i = 0; i < N; ++i) {
        A[i + 1] = A[i] + (__int128)count[i] * pow2;
        pow2 *= 2;
    }

    B[N] = 0;
    for (int i = N - 1; i >= 0; --i) {
        B[i] = (__int128)count[i] + 2 * B[i + 1];
    }

    __int128 max_val = 0;
    bool first_p = true;
    for (int p = 1; p < N; ++p) {
        __int128 current_score = A[p] + B[p];
        if (first_p || current_score > max_val) {
            max_val = current_score;
            first_p = false;
        }
    }

    // The final answer fits in a signed 64-bit integer.
    long long result = (long long)max_val;
    cout << result << endl;

    return 0;
}

This editorial was generated by gemini-3-flash-thinking.

投稿日時:
最終更新: