Problem Analysis
At its core this is a combinatorics problem about counting subsets. A cube is fully described by the set of six distinct digits printed on its faces - the physical orientation of the faces is irrelevant, because any face can be rotated into view. So a cube is simply a 6-element combination (an unordered selection, with no element repeated) drawn from the ten digits {0, ..., 9}. The number of such combinations is the binomial coefficient C(10, 6) = 210. Recognising this change of representation is the entire trick: a tangible object with rotatable faces becomes a plain set, and the problem dissolves into counting.
An "arrangement" is a pair of cubes, and the problem states the pair is unordered: cube A beside cube B is the same arrangement as cube B beside cube A. Counting unordered pairs with repetition allowed - two identical cubes are a legitimate physical arrangement - gives C(210 + 1, 2) = 22,155 candidate pairs. That is a tiny number, so a brute-force search over every pair is the natural and optimal strategy. For each pair I test the nine two-digit squares below 100 (01, 04, 09, 16, 25, 36, 49, 64, 81). Two observations make that test clean: each square can be formed with either cube supplying the tens digit, so the check considers both orientations; and the 6/9 flip rule means a face showing 6 can also serve as 9 and vice versa, so "can this cube show a 6 or 9?" reduces to "is 6 or 9 present?". The overall complexity is O(C(10,6)^2 * 9) - effectively constant for fixed input, completing in well under a millisecond in C.
Solution Approach
Brute-Force Combination Enumeration (Python and C)
Both files implement the identical algorithm; only the language idioms differ. I chose brute force deliberately because, as the analysis shows, the search space is minuscule. When a problem fits comfortably under roughly 10^7 operations, correctness and clarity matter far more than algorithmic cleverness.
Step 1 - enumerate the cubes. In Python I call itertools.combinations(range(10), 6), which yields all 210 six-element subsets in lexicographic order. In C I reproduce the same enumeration with six nested loops whose index bounds enforce a strictly increasing sequence (a < b < c < d < e < f), storing the digits in a fixed all_cubes[210][6] array. Both produce exactly the same 210 cubes.
Step 2 - encode the square targets. The Python solution computes the nine squares at runtime, formatting each as a two-character string and splitting it into tens and units digits. The C solution hard-codes the nine digit pairs as a static int squares[9][2]. Both are equally correct; the C version trades a little flexibility for directness.
Step 3 - the display predicate. The helper can_display(cube, digit) returns true if the digit is on the cube, or - when the target is 6 or 9 - if either 6 or 9 is present. This single function captures the only subtle rule in the problem, so I isolated it rather than scattering the condition through the pairing loop.
Step 4 - the pair check. can_pair_display_all loops over the nine square pairs (a, b) and requires that for each one, either (cube1 shows a and cube2 shows b) or (cube1 shows b and cube2 shows a). The disjunction covers both physical placements. If any square fails, the pair is rejected immediately - a short-circuit that prunes most pairs after only a few iterations.
Step 5 - count unordered pairs. The outer loops run for i in range(n): for j in range(i, n). Starting j at i (not i + 1) counts each unordered pair once and crucially admits a cube paired with an identical copy of itself.
