CCCGuide
Data Structures, Simulation and Ad-hoc (J2–J4)

Simulation

frequent

A simulation follows a process step by step, keeping track of the current state and applying the operations described in the problem.

Before writing the loop, check the time complexity. Estimate:

number of steps × work per step

If this fits within the time limit, a direct simulation is usually sufficient. If not, look for a more efficient approach.

Simulation problems usually come in three forms:

  1. Apply the operations — perform the given moves in order (Flipper).
  2. Generate and test — generate a bounded set of possibilities and check each one (Cyclic Shifts).
  3. Step through time — advance the state one unit at a time until the process ends (Arrival Time).

J4 Walkthrough: Flipper2019 · J4 · Original problem · DMOJ

You are trying to pass the time while at the optometrist. You notice there is a grid of four numbers:

12
34

You see lots of mirrors and lenses at the optometrist, and wonder how flipping the grid horizontally or vertically would change the grid.

Specifically, a “horizontal” flip (across the horizontal centre line) would take the original grid of four numbers and result in:

34
12

A “vertical” flip (across the vertical centre line) would take the original grid of four numbers and result in:

21
43

Your task is to determine the final orientation of the numbers in the grid after a sequence of horizontal and vertical flips.

The input consists of one line, composed of a sequence of at least one and at most 1 000 000 characters. Each character is either H, representing a horizontal flip, or V, representing a vertical flip.

For 8 of the 15 available marks, there will be at most 1 000 characters in the input.

Output the final orientation of the four numbers. Specifically, each of the two lines of output will contain two integers, separated by one space.

HV

Output for Sample Input 1

4 3
2 1

VVHH

Output for Sample Input 2

1 2
3 4

Solution

The statement hands us a 2×2 grid and a string of flips, so the natural plan is to do exactly what it says: start from the grid 1 2 / 3 4 and apply the flips one at a time.

A horizontal flip swaps the two rows. A vertical flip swaps the two entries within each row. Each flip is at most a couple of swaps, and the input has at most 1 000 000 characters, so the whole solution is one pass over the string with constant work per step. Running the estimate: a million steps times a couple of swaps each — nowhere near any limit.

The subtasks hint that the setters expected brute force to struggle: 8 of the 15 marks are for inputs of at most 1 000 characters. But a 2×2 grid is so small that simulating all 1 000 000 flips is still instant.

There is a shortcut worth knowing here. Doing the same flip twice returns the grid to where it started, and a horizontal and vertical flip commute — either order produces the same 180° rotation. So only the parity of the number of H's and V's actually matters. That saves a pass over the string, but the direct simulation is easier to get right on the first try, and in a contest that is usually the better trade.

Implementation

grid = [[1, 2], [3, 4]]

for c in input():
    if c == "H":
        grid[0], grid[1] = grid[1], grid[0]
    else:
        for row in grid:
            row[0], row[1] = row[1], row[0]

for row in grid:
    print(*row)

J4 Walkthrough: Cyclic Shifts2020 · J4 · Original problem · DMOJ

Thuc likes finding cyclic shifts of strings. A cyclic shift of a string is obtained by moving characters from the beginning of the string to the end of the string. We also consider a string to be a cyclic shift of itself. For example, the cyclic shifts of ABCDE are:

ABCDE, BCDEA, CDEAB, DEABC, and EABCD.

Given some text, TT, and a string, SS, determine if TT contains a cyclic shift of SS.

The input will consist of exactly two lines containing only uppercase letters. The first line will be the text TT, and the second line will be the string SS. Each line will contain at most 10001000 characters.

For 6 of the 15 available marks, SS will be exactly 33 characters in length.

Output yes if the text, TT, contains a cyclic shift of the string, SS. Otherwise, output no.

ABCCDEABAA
ABCDE

Output for Sample Input 1

yes

Explanation of Output for Sample Input 1

CDEAB is a cyclic shift of ABCDE and it is contained in the text ABCCDEABAA.

ABCDDEBCAB
ABA

Output for Sample Input 2

no

Explanation of Output for Sample Input 2

The cyclic shifts of ABA are ABA, BAA, and AAB. None of these shifts are contained in the text ABCDDEBCAB.

Solution

The definition does most of the work here. A cyclic shift of S moves some characters from the front to the back, and S counts as a cyclic shift of itself. Since S has at most 1000 characters, there are at most 1000 shifts in total: shift by 0 positions, by 1, by 2, and so on.

Generating every shift — S[i:] + S[:i] for each starting position i — and checking whether T contains it as a substring covers all cases. Both languages have a built-in substring search that is heavily optimized: Python's in operator and C++'s find. There is no need to hand-roll the search.

The candidate set comes straight from the definition, and the standard library handles the search. The estimate is comfortable too — a thousand shifts times a fast scan of a thousand-character text, well under the budget.

Two details worth noting. If S is longer than T, no shift can fit, but the substring check simply fails for every shift, so no special case is needed. And the shift by 0 positions is S itself, which handles the "a string is a cyclic shift of itself" rule automatically.

Implementation

T = input()
S = input()

found = "no"
for i in range(len(S)):
    shift = S[i:] + S[:i]
    if shift in T:
        found = "yes"
        break

print(found)

J4 Walkthrough: Arrival Time2016 · J4 · Original problem · DMOJ

Fiona commutes to work each day. If there is no rush-hour traffic, her commute time is 2 hours. However, there is often rush-hour traffic. Specifically, rush-hour traffic occurs from 07:00 (7am) until 10:00 (10am) in the morning and 15:00 (3pm) until 19:00 (7pm) in the afternoon. During rush-hour traffic, her speed is reduced by half.

She leaves either on the hour (at XX:00), 20 minutes past the hour (at XX:20), or 40 minutes past the hour (at XX:40).

Given Fiona’s departure time, at what time does she arrive at work?

The input will be one line, which contains an expression of the form HH:MM, where HH is one of the 24 starting hours (00, 01, …\ldots, 23) and MM is one of the three possible departure minute times (00, 20, 40).

Output the time of Fiona’s arrival, in the form HH:MM.

05:00

Output for Sample Input 1

07:00

Explanation for Output for Sample Input 1

Fiona does not encounter any rush-hour traffic, and leaving at 5am, she arrives at exactly 7am.

07:00

Output for Sample Input 2

10:30

Explanation for Output for Sample Input 2

Fiona drives for 3 hours in rush-hour traffic, but only travels as far as she normally would after driving for 1.5 hours. During the final 30 minutes (0.5 hours) she is driving in non-rush-hour traffic.

23:20

Output for Sample Input 3

01:20

Explanation for Output for Sample Input 3

Fiona leaves at 11:20pm, and with non-rush-hour traffic, it takes two hours to travel, so she arrives at 1:20am the next day.

Solution

The awkward part of this problem is clock arithmetic. Fiona covers two hours of distance, but rush hour halves her speed, and her drive might start inside rush hour, end inside it, span both rush-hour windows, or cross midnight. Handling these cases directly with time arithmetic invites mistakes.

Simulation replaces all of that case work with a loop. Keep two numbers: the current time t in minutes, and how much of the trip is done, measured in minutes of normal-speed travel. Advance one minute at a time. If the minute we are driving through falls in a rush-hour window — 07:00 to 10:00 is minutes 420 through 599, and 15:00 to 19:00 is minutes 900 through 1139 — it covers half a normal minute of distance, otherwise it covers one. Stop once two full hours of distance are covered.

To stay in integers, measure progress in half-minutes: a rush-hour minute adds 1, a regular minute adds 2, and the trip needs 240. Taking t modulo 1440 handles crossing midnight, as in the third sample. The loop is bounded as well — every minute adds at least 1 to the progress, so it runs for at most 240 minutes — and a few hundred constant-work steps is as cheap as simulation gets.

Check the second sample against the loop: leaving at 07:00, Fiona spends minutes 420 through 599 in rush hour — 180 minutes covering 90 normal minutes of distance — then needs 30 more regular minutes, arriving at 10:30. The loop also explains why arrivals are not always multiples of 20 minutes even though departures are: the trip ends wherever the 240 half-minutes land, and that can be any minute.

Implementation

h, m = input().split(":")
t = int(h) * 60 + int(m)

travelled = 0  # in half-minutes; the trip needs 240
while travelled < 240:
    minute = t % 1440
    if 420 <= minute < 600 or 900 <= minute < 1140:
        travelled += 1
    else:
        travelled += 2
    t += 1

t %= 1440
print(f"{t // 60:02d}:{t % 60:02d}")

Summary

All three problems above were small enough that a direct simulation was the simplest approach. The difficulty was never the loop itself — it was choosing the right state to track. In Flipper, state was just a 2×2 grid. In Cyclic Shifts, it was a set of candidate strings. In Arrival Time, switching from clock time to half-minutes eliminated all the messy time arithmetic.

When a simulation feels complicated, the first question to ask is whether the state can be reframed.

On this page

Contributors