Skip to content
Vamshi Jandhyala

Books · The Riddler

Chapter 260

Can You Catch The Free T-Shirt?

The Riddler for April 10, 2020. The Express launches T-shirts from a cannon at a random angle and asks which row is the safest bet to catch one. The Classic watches spam comments breed replies and asks how many posts pile up in three days.

Riddler Express

A T-shirt cannon in front of Row 11 can just reach the back of Row 100100 (no farther), with no air resistance. The launch angle is uniform between 00^\circ (flat) and 9090^\circ (straight up). Which row should you sit in to maximise your chance of catching the shirt?

The Riddler, FiveThirtyEight, April 10, 2020(original post)

Solution

A projectile launched at angle θ\theta travels a horizontal distance proportional to sin2θ\sin 2\theta, and the maximum range (at θ=45\theta = 45^\circ) reaches the back of Row 100100. Measuring distance in rows, the shirt lands at R(θ)=100sin2θ.R(\theta) = 100\,\sin 2\theta . As θ\theta sweeps uniformly from 00^\circ to 9090^\circ, the landing row RR runs from 00 up to 100100 and back to 00. The chance of landing in a given row is governed by how fast RR changes with θ\theta: where RR changes slowly, many angles funnel the shirt into the same row. Since dRdθ=200cos2θ\tfrac{dR}{d\theta} = 200\cos 2\theta vanishes at θ=45\theta = 45^\circ, the curve is flattest at its peak, so a wide band of angles all land near the maximum. The most likely landing row is therefore the very back, Row 100,\boxed{\text{Row } 100}, caught about 9%9\% of the time. (This is the same reason a rainbow is bright at its maximum-deflection angle: probability piles up where the mapping is flat.)

The computation

Encode the launch: draw angles uniformly, send each shirt to row 100sin2θ\lceil 100\sin 2\theta\rceil, and tally which row catches the most.

import numpy as np, math
from collections import Counter
th = np.random.default_rng(0).uniform(0, math.pi/2, 20_000_000)
rows = np.clip(np.ceil(100*np.sin(2*th)).astype(int), 1, 100)
cnt = Counter(rows.tolist())
best = max(range(1, 101), key=lambda r: cnt[r])
print(best, round(cnt[best]/len(th), 3))     # 100 0.09

Row 100100 catches the most shirts, about 9%9\% of launches, as boxed.

Riddler Classic

Spam comments arrive on the column as a Poisson process: on average one brand-new (top-level) spam comment per day. Every spam post, comment or reply alike, itself attracts replies at an average rate of one per day. Over three days, how many spam posts (comments plus replies) can you expect in total?

The Riddler, FiveThirtyEight, April 10, 2020(original post)

Solution

This is a branching process in continuous time. Consider one post that has τ\tau days left in which to attract replies, and let f(τ)f(\tau) be the expected total number of posts in its whole reply tree, counting the post itself. The post spawns replies at rate 11; a reply born after uu days then has τu\tau - u days of its own, contributing f(τu)f(\tau - u). So f(τ)=1+0τf(τu)du=1+0τf(v)dv.f(\tau) = 1 + \int_0^{\tau} f(\tau - u)\,du = 1 + \int_0^{\tau} f(v)\,dv . Differentiating gives f(τ)=f(τ)f'(\tau) = f(\tau) with f(0)=1f(0) = 1, so f(τ)=eτf(\tau) = e^{\tau}.

The top-level comments themselves arrive at rate 11 over the three days, and a top-level comment born at time ss has τ=3s\tau = 3 - s days remaining, hence an expected tree of e3se^{3-s} posts. Integrating over their arrival times, E[total]=03e3sds=03evdv=e3119.09.\mathbb{E}[\text{total}] = \int_0^{3} e^{3-s}\,ds = \int_0^{3} e^{v}\,dv = e^{3} - 1 \approx \boxed{19.09}. (Equivalently, the expected count S(t)S(t) obeys dS/dt=SdS/dt = S once the column itself is treated as the seed post, giving S(3)=e3S(3) = e^3 and e31e^3 - 1 genuine spam posts.)

The computation

Encode the actual process: generate top-level arrivals as a rate-11 Poisson process on [0,3][0,3], let every post breed replies at rate 11 until day 33, and average the total count.

import random, math
rng = random.Random(0); T = 3.0; trials = 200_000; total = 0
for _ in range(trials):
    stack = []
    t = rng.expovariate(1.0)
    while t < T: stack.append(t); t += rng.expovariate(1.0)   # top-level arrivals
    n = 0
    while stack:
        born = stack.pop(); n += 1
        c = born + rng.expovariate(1.0)
        while c < T: stack.append(c); c += rng.expovariate(1.0)   # replies of this post
    total += n
print(total/trials, math.e**3 - 1)            # ~19.05, 19.086

The simulated mean (about 19.0519.05) matches e3119.09e^3 - 1 \approx 19.09, as boxed.