Contest Solution: Hailstones
Your outer loop…


with open('hail.in') as f:
    l = f.readline()
    while l:
        …
        l = f.readline()



… should be more idiomatically written as:

with open('hail.in') as f:
    for l in f:
        …


Also, the inner counting loop, with i += 1, would be more idiomatically written using for i in itertools.count(): ….



This code looks like you are code-golfing:


while l:
    n, a, b, i = int(l[:-1]), [], { 4, 2, 1 }, 0



While n and i are acceptable, the other one-letter names are too cryptic.  Renaming l → line, a → seq, and b → steady would make the code much easier to understand.

Why do you write l[:-1]?  Is the -1 to strip the trailing newline?  You don't need to do that: int() automatically disregards trailing whitespace.



The code for counting the steps for each n should be extracted into a separate function, since it is a deterministic function of n.

You don't need to build the list a to determine how long the sequence is.

Use the // operator for integer division.  Floating-point division is wasteful.



Instead of calling print() with multiple arguments, use one of the string-formatting mechanisms in Python (e.g. str.format() or f-strings).

Suggested solution

from itertools import count

def steps(n):
    """
    Count the number of steps for the hailstone sequence starting at n to
    reach a steady state of 4, 2, 1, 4, 2, 1, ...
    """
    for i in count():
        if n in { 4, 2, 1 }:
            return i
        n = n // 2 if n % 2 == 0 else 3 * n + 1

with open('hail.in') as f:
    for line in f:
        n = int(line)
        print('{0} steps were necessary for {1}.'.format(steps(n), n))