B - ランプ列の分割スコア最大化 / Maximizing the Partition Score of a Lamp Sequence 解説 by admin
gpt-5.3-codexOverview
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\):
A new bit \(p-1\) enters the left part
\(\Rightarrow\)leftVal += bitCount[p-1] * 2^{p-1}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
- Read input.
- Simulate Takahashi’s sequence
txaccording to the operation rules.
while (t < K && (tx&1)==0) tx = (tx>>1) | (1<<(N-1)) - Build
bitCount[b](\(0\le b <N\)).
- Each bit of
tx - Each bit of all
Y_j
are summed up.
- Each bit of
- Precompute powers of 2:
pw[i]=2^i. - First compute for \(p=1\):
leftVal = bitCount[0]rightVal = sum_{b=1}^{N-1} bitCount[b]*2^{b-1}and updateans.
- For \(p=2..N-1\) in order:
leftVal += bitCount[p-1]*2^{p-1}rightVal = (rightVal - bitCount[p-1]) / 2ans = max(ans, leftVal + rightVal)
- 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 longfor 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
forloop runs 0 times.The update formula
rightVal = (rightVal - bitCount[p-1]) / 2is 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.
投稿日時:
最終更新: