#!/usr/bin/env python3 import sys import numpy as np from scipy.fft import fftn, ifftn, next_fast_len BLACK = ord('B') WHITE = ord('W') def solve() -> None: tokens = sys.stdin.buffer.read().split() if not tokens: return x_size, y_size, z_size = map(int, tokens[:3]) cells = np.frombuffer(b''.join(tokens[3:]), dtype=np.uint8).reshape( 2, z_size, y_size, x_size ) first, second = cells # The real part of # (A_black + i A_white) * (B_white - i B_black) # is A_black * B_white + A_white * B_black. first_packed = (first == BLACK).astype(np.complex128) first_packed.imag = first == WHITE reversed_second = second[::-1, ::-1, ::-1] second_packed = (reversed_second == WHITE).astype(np.complex128) second_packed.imag = -(reversed_second == BLACK).astype(np.float64) convolution_shape = ( 2 * z_size - 1, 2 * y_size - 1, 2 * x_size - 1, ) transform_shape = tuple(next_fast_len(length) for length in convolution_shape) transformed = fftn( first_packed, s=transform_shape, workers=-1, overwrite_x=True ) transformed *= fftn( second_packed, s=transform_shape, workers=-1, overwrite_x=True ) convolution = np.rint( ifftn(transformed, workers=-1, overwrite_x=True).real[ :convolution_shape[0], :convolution_shape[1], :convolution_shape[2], ] ).astype(np.int64) # Fold every linear-convolution coordinate modulo its original axis. convolution[:, :, :x_size - 1] += convolution[:, :, x_size:] convolution = convolution[:, :, :x_size] convolution[:, :y_size - 1, :] += convolution[:, y_size:, :] convolution = convolution[:, :y_size, :] convolution[:z_size - 1, :, :] += convolution[z_size:, :, :] convolution = convolution[:z_size, :, :] print(int(convolution.min())) if __name__ == '__main__': solve()