C - スイッチと電球 / Switches and Light Bulbs Editorial by admin Editorial for printing
Claude Opus 5 (High)Overview
There is a light bulb in each cell of an \(H \times W\) grid. Pressing the switch at a specified cell toggles the state of the light bulb at that cell and its vertically and horizontally adjacent neighboring cells. The problem asks you to find the state of each light bulb after \(Q\) operations.
Analysis
Is a Naive Simulation Sufficient?
At first glance, “updating the grid for each query” may seem like a heavy operation, but in this problem, at most 5 cells change their state in a single operation. Therefore, the total number of cells that change across all \(Q\) operations is at most \(5Q = 5 \times 10^5\).
In other words, simply performing the naive approach of “toggling the pressed cell and its 4 neighbors” each time takes only \(O(Q)\) time for the operations. There is no need for complex algorithms (such as 2D difference arrays / the imos method).
So, What Is the Challenge?
The essential challenge of this problem is the input/output size.
- Since the grid size satisfies \(H \times W \leq 10^6\), the input contains up to roughly \(10^6\) characters, and the output is also around \(10^6\) characters (roughly \(10^6 + H\) characters including newlines).
- Furthermore, although there is a constraint of \(H \leq 2 \times 10^4\), the upper bound on \(W\) is only indirectly determined by \(H \times W \le 10^6\). Thus, the grid could be “very wide” such as \(H = 1, W = 10^6\), or shaped like \(H = 2\times10^4, W = 50\).
With this scale:
- Reading/writing character by character using
cin >> ch/cout << ch - Flushing each line with
endl - Performing string concatenation each time
implementations like these can cause TLE due to heavy constant-factor overhead, even if the theoretical time complexity is \(O(HW)\).
Representing the Toggle
Since the state of each light bulb is 0 or 1, toggling can be represented using XOR 1 (^= 1). While it is naturally understood from the properties of XOR that “only the parity of the number of presses matters,” in this problem we can simply toggle the values directly, so there is not even a need to count parities.
Concrete Example
For \(H = 3, W = 3\):
000
000
000
pressing the switch at cell \((2,2)\) gives
010
111
010
and then pressing \((1,2)\) toggles \((1,1),(1,2),(1,3),(2,2)\), resulting in
101
101
010
(nothing is done for the cell above \((1,2)\) because it does not exist). The key is to avoid processing cells that fall outside the grid boundaries.
Algorithm
- Represent the grid as a 1-dimensional array
g. Map cell \((i, j)\) (0-indexed) tog[i * W + j]. - Read the input strings and store the 0/1 values in
g. - For each query \((R_k, C_k)\), convert it to 0-indexed coordinates and let
idx = r * W + c:g[idx] ^= 1- If
r > 0,g[idx - W] ^= 1(up) - If
r < H-1,g[idx + W] ^= 1(down) - If
c > 0,g[idx - 1] ^= 1(left) - If
c < W-1,g[idx + 1] ^= 1(right)
Make sure to check boundaries using the “row and column indices” (checking only with idx can cause wrap-around between adjacent rows).
4. Finally, pack g into a single large character buffer and output it all at once.
Complexity
- Time Complexity: \(O(HW + Q)\)
- Space Complexity: \(O(HW)\)
Since \(HW \le 10^6\) and \(Q \le 10^5\), this will easily pass within the time limit.
Implementation Details
Use a 1D array instead of a 2D array: Since \(H\) and \(W\) are determined at runtime and the constraint is on their product (\(H \times W \le 10^6\)), allocating a single
vector<char>of size \(H \times W\) and accessing it viai * W + jis straightforward and faster than usingvector<vector<char>>. While anintis sufficient since the indices are around \(10^6\), casting tosize_tis safe practice.Fast Input: In this code, input is read in bulk using
freadand parsed manually. Parsing integers withreadInt()and reading grid rows by skipping characters until'0'/'1'is encountered before reading \(W\) characters avoids issues with newlines and whitespaces. If you usecinin C++, be sure to includeios::sync_with_stdio(false); cin.tie(nullptr);, and read the grid row by row asstrings.Fast Output: Printing the output character by character in a
forloop withcout <<tends to be slow. A reliable approach is to allocate a buffer forH * (W + 1)characters (including one newline character at the end of each row), fill it, and output it all at once using a singlefwritecall. Never useendl, as it flushes the output buffer every time.Boundary check mistakes: The most common bug is checking horizontal neighbors simply with
idx - 1andidx + 1without verifying column boundaries, causing indices to wrap around to adjacent rows at the grid edges. Make sure to checkc > 0andc < W - 1. It is also a good idea to verify that the implementation works correctly for edge cases like \(W = 1\) or \(H = 1\).Toggling with XOR: While
g[idx] = 1 - g[idx]is fine,g[idx] ^= 1is concise and fast.Source Code
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
static char buf[1 << 25];
static size_t bufLen = 0, bufPos = 0;
static inline int gc() {
if (bufPos == bufLen) {
bufLen = fread(buf, 1, sizeof(buf), stdin);
bufPos = 0;
if (bufLen == 0) return -1;
}
return (unsigned char)buf[bufPos++];
}
static inline int readInt() {
int c = gc();
while (c != -1 && (c < '0' || c > '9')) c = gc();
int x = 0;
while (c >= '0' && c <= '9') { x = x * 10 + (c - '0'); c = gc(); }
return x;
}
int main() {
int H = readInt();
int W = readInt();
vector<char> g((size_t)H * W);
for (int i = 0; i < H; i++) {
int c = gc();
while (c != '0' && c != '1') c = gc();
size_t base = (size_t)i * W;
for (int j = 0; j < W; j++) {
g[base + j] = (char)(c - '0');
c = gc();
}
}
int Q = readInt();
for (int k = 0; k < Q; k++) {
int r = readInt() - 1;
int c = readInt() - 1;
size_t idx = (size_t)r * W + c;
g[idx] ^= 1;
if (r > 0) g[idx - W] ^= 1;
if (r < H - 1) g[idx + W] ^= 1;
if (c > 0) g[idx - 1] ^= 1;
if (c < W - 1) g[idx + 1] ^= 1;
}
// output
size_t outSize = (size_t)H * (W + 1) + 1;
vector<char> out(outSize);
size_t p = 0;
for (int i = 0; i < H; i++) {
size_t base = (size_t)i * W;
for (int j = 0; j < W; j++) out[p++] = (char)('0' + g[base + j]);
out[p++] = '\n';
}
fwrite(out.data(), 1, p, stdout);
return 0;
}
This editorial was generated by claude5opus-high.
posted:
last update: