公式

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

gpt-5.3-codex

Overview

After updating Takahashi’s sequence \(X\) “at most \(K\) times, only while the leftmost bit is 0,” we choose a common split position \(p\) across all sequences (Takahashi’s 1 sequence + Aoki’s \(M\) sequences), and maximize the total \(A+B\), where \(A\) is the sum of values of the left parts and \(B\) is the sum of values of the right parts.
The key insight is that by focusing on how many sequences have a 1 at each bit position, we can efficiently evaluate each \(p\).

Analysis

First, let’s organize Takahashi’s operation.
Looking at the leftmost bit (in this problem, the least significant bit):

  • If it’s 1, stop immediately
  • If it’s 0, discard that bit and append a 1 to the right end

So, expressed in terms of integers, one operation is: - Right shift >> 1 - Set the most significant bit (bit \(N-1\)) to 1

In other words, it’s the same as: tx = (tx >> 1) | (1ULL << (N-1)) We repeat this “up to \(K\) times” and “only while the LSB is 0.”


Next, the score after splitting. If the split position is \(p\), for each sequence:

  • The left part evaluates the original bits \(0..p-1\) with weights \(2^0..2^{p-1}\) as-is
  • The right part evaluates the original bits \(p..N-1\) repacked with weights \(2^0..2^{N-p-1}\)

The important point here is that instead of looking at each sequence individually, we aggregate “the number of sequences where bit \(b\) is 1” as bitCount[b].
Then:

\[ A = \sum_{b=0}^{p-1} \text{bitCount}[b]\cdot 2^b \]

\[ B = \sum_{b=p}^{N-1} \text{bitCount}[b]\cdot 2^{b-p} \]

So \(A+B\) can be computed using only bitCount.


Naively computing the above formula from scratch for each \(p\) takes \(O(N^2)\) (scanning all bits for each \(p\)).
Since \(N\le 46\), this might seem feasible at first glance, but a more organized implementation naturally updates the boundary one step at a time.

  • leftVal = current \(A\)
  • rightVal = current \(B\)

When advancing from \(p-1 \to p\):

  1. A new bit \(p-1\) enters the left part
    \(\Rightarrow\) leftVal += bitCount[p-1] * 2^{p-1}

  2. The right part “removes the first term bitCount[p-1] and shifts everything right by 1 bit”
    \(\Rightarrow\) rightVal = (rightVal - bitCount[p-1]) / 2

This allows us to scan all \(p\) in \(O(N)\).

Algorithm

  1. Read input.
  2. Simulate Takahashi’s sequence tx according to the operation rules.
    while (t < K && (tx&1)==0) tx = (tx>>1) | (1<<(N-1))
  3. Build bitCount[b] (\(0\le b <N\)).
    • Each bit of tx
    • Each bit of all Y_j
      are summed up.
  4. Precompute powers of 2: pw[i]=2^i.
  5. First compute for \(p=1\):
    • leftVal = bitCount[0]
    • rightVal = sum_{b=1}^{N-1} bitCount[b]*2^{b-1} and update ans.
  6. For \(p=2..N-1\) in order:
    • leftVal += bitCount[p-1]*2^{p-1}
    • rightVal = (rightVal - bitCount[p-1]) / 2
    • ans = max(ans, leftVal + rightVal)
  7. Output ans.

Complexity

  • Time complexity: \(O(NM + N + \min(K,N))\) (effectively \(O(NM)\))
  • Space complexity: \(O(N + M)\) (in an implementation that stores Y)

Implementation Notes

  • Use unsigned long long for bit operations (safe since \(N\le 46\)).

  • Manage the answer and sums with long long (the problem guarantees they fit in 64 bits).

  • When \(M=0\) and there is no second line in the input format, this code naturally handles it since the for loop runs 0 times.

  • The update formula rightVal = (rightVal - bitCount[p-1]) / 2 is an integer operation based on algebraic transformation and is always exactly divisible.

    Source Code

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

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

    int N, M;
    long long K;
    unsigned long long X;
    cin >> N >> K >> M >> X;

    vector<unsigned long long> Y(M);
    for (int i = 0; i < M; i++) cin >> Y[i];

    // Simulate Takahashi's process on X:
    // while LSB is 0 and operations < K:
    //   X = (X >> 1) + (1ULL << (N-1))
    unsigned long long tx = X;
    long long t = 0;
    while (t < K && ((tx & 1ULL) == 0ULL)) {
        tx >>= 1;
        tx |= (1ULL << (N - 1));
        t++;
    }

    // bitCount[b] = number of sequences (tx + all Y) whose bit b is 1, 0-based from left(LSB side)
    vector<long long> bitCount(N, 0);
    for (int b = 0; b < N; b++) {
        if ((tx >> b) & 1ULL) bitCount[b]++;
    }
    for (auto v : Y) {
        for (int b = 0; b < N; b++) {
            if ((v >> b) & 1ULL) bitCount[b]++;
        }
    }

    // For split p (1..N-1):
    // A = sum_{b=0..p-1} bitCount[b] * 2^b
    // B = sum_{b=p..N-1} bitCount[b] * 2^(b-p)
    // maximize A+B
    long long ans = LLONG_MIN;

    // Precompute powers of two up to N
    vector<long long> pw(N + 1, 1);
    for (int i = 1; i <= N; i++) pw[i] = pw[i - 1] << 1;

    // Compute initial for p=1
    // leftVal = A for current p
    // rightVal = B for current p
    long long leftVal = bitCount[0] * pw[0];
    long long rightVal = 0;
    for (int b = 1; b < N; b++) {
        rightVal += bitCount[b] * pw[b - 1];
    }
    ans = max(ans, leftVal + rightVal);

    for (int p = 2; p <= N - 1; p++) {
        // Move boundary from p-1 to p:
        // New left adds bit p-1 with weight 2^(p-1)
        leftVal += bitCount[p - 1] * pw[p - 1];

        // right part indices shift:
        // old right had sum_{b=p-1..N-1} bitCount[b]*2^(b-(p-1))
        // new right is sum_{b=p..N-1} bitCount[b]*2^(b-p)
        // => newRight = (oldRight - bitCount[p-1]) / 2
        rightVal = (rightVal - bitCount[p - 1]) / 2;

        ans = max(ans, leftVal + rightVal);
    }

    cout << ans << '\n';
    return 0;
}

This editorial was generated by gpt-5.3-codex.

投稿日時:
最終更新: