Skip to content
CCC Python Course

Building a valid witness

Module
M5.1
Lesson
1 of 1
Reading time
5 min

In this lesson

  • Build any valid witness instead of testing all possibilities.
  • Start from simple patterns and handle extreme cases.
  • Use symmetry and invariants to constrain the search.
  • Verify output before submitting a solution.

Some contest problems never ask for a maximum, a minimum or a count. They ask you to build any arrangement that satisfies a set of constraints, and to say "Impossible" if none exists. These are constructive problems: your job is not to search a space of candidates, it is to produce one valid answer directly. Watch for phrasing like "output any valid sequence," "construct a valid grid," or "find any arrangement" — that phrasing is the signal. Senior contests lean on this style heavily: 5 of the last 8 S3 problems have asked for exactly this kind of construction.

Starting with a simple pattern

The way in is to try the simplest pattern that could possibly work, and only complicate it once that pattern actually fails.

Need N numbers where every pair of adjacent numbers differs by at least 1? Try 1, 2, 3, ..., N. Every adjacent pair differs by exactly 1, so the constraint holds without any further checking. Need a binary string of length N with at least one 0 and at least one 1? Start from all zeros, then flip one character to a 1. Both are valid, and neither took any search to find.

Build the pattern, check that it satisfies every constraint the problem states, and if it does, that is your answer.

Handling the impossible case

Not every set of constraints has a solution, and the problem expects you to detect that and print "Impossible" instead.

Try the simple pattern first, and check it against the constraints. If it fails, ask whether some other construction could still work, or whether the constraints themselves rule out any answer. Often, if the most natural pattern cannot satisfy the constraints, nothing can.

Take "N different numbers, all at least 100." For N = 200, 100, 101, ..., 299 gives 200 distinct numbers, all at least 100: done. For N = 1000, the same idea just needs a longer run, 100 through 1099. But if the problem also demands at least 2 numbers and N is 1, no construction helps, since the constraints themselves are contradictory before you have picked a single value.

Symmetry and mirroring

Some constraints get easier the moment you build in symmetry from the start. A grid that has to read the same forwards and backwards only needs one half chosen; mirror it, and the symmetry constraint is satisfied automatically, with nothing left to check. The same idea covers a grid symmetric about its centre (choose one quadrant, mirror the rest) or a palindromic sequence (choose the first half, mirror it into the second).

Building the symmetry in cuts the number of choices roughly in half, since you are only ever deciding N/2 positions instead of N. Fewer positions to choose also means fewer chances to introduce a mistake.

A worked example

Given N and M, build an N-by-M grid of characters where every row has the same number of vowels and every column has the same number of vowels, or report "Impossible" if that cannot be done.

Try the simplest pattern: fill the whole grid with 'a'. Every row now has exactly M vowels, and every column has exactly N vowels, both constants across all rows and all columns. This works whenever N and M are at least 1. If either is 0, the grid is empty, and a constraint over zero rows or zero columns holds vacuously.

examples/grid_vowels.py
import sys

def main() -> None:    input_data = sys.stdin.read().split()    if not input_data:        return
    n = int(input_data[0])    m = int(input_data[1])
    if n == 0 or m == 0:        return
    for i in range(n):        row = "a" * m        print(row)

if __name__ == "__main__":    main()

Input

3 4

Output

aaaa
aaaa
aaaa
Build a grid with equal vowels per row and column

The program reads N and M, and when both are positive it prints N rows, each M copies of 'a'. Every row has M vowels, every column has N vowels, and the grid the code prints for 3 4 is exactly three rows of aaaa. When N or M is 0, the loop never runs and nothing prints, which is still a correct answer to a vacuous constraint.

Add a second constraint on top: each row must also have an equal number of vowels and consonants. That forces M to be even, since you cannot split an odd length into two equal halves. When M is even, the simple pattern still adapts easily: fill the first M/2 characters of each row with 'a' and the rest with 'b', giving M/2 vowels and M/2 consonants per row. When M is odd, no arrangement can satisfy the new constraint, and the answer is "Impossible."

Extreme cases and boundary conditions

Before you submit, run the construction through the edges of the input space by hand: N = 1 and M = 1, N = 0 or M = 0 if the problem allows them, and the largest sizes the constraints permit. If a constraint bounds values rather than sizes, check the smallest allowed value, the largest, and something in the middle.

A construction that passes the sample cases but breaks on an edge case is the most common way these solutions fail. Checking N = 1, M = 1 by hand takes seconds; checking it before you submit is far cheaper than a wrong answer on the actual judge.

Putting it together

A constructive solution usually follows the same shape: read the input, try the simplest pattern that could satisfy every constraint, and output it if it does. If it does not, either adjust the pattern to handle the failing constraint, the way the vowel-and-consonant grid extended the all-'a' grid, or show that the constraints contradict each other and no construction exists. Some problems layer several constraints on top of each other; each layer usually just means adjusting the pattern a little further, not throwing it out and starting over.

Practice

Try these on the judges. Each link opens the problem on WMOJ or DMOJ.

  1. 2023 S3
    Palindromic Poster (opens on WMOJ in a new tab) WMOJ

    Build a palindromic poster on a grid by choosing characters for each cell.

  2. 2019 S3
    Arithmetic Square (opens on DMOJ in a new tab) DMOJ

    Fill a grid so all rows and columns have the same sum.

    Why DMOJ: An older constructive-casework problem with the same build-and-verify approach.