···11+import fileinput
22+from collections import Counter, defaultdict, deque, namedtuple # NOQA
33+44+# Read problem input.
55+data = ''.join([line for line in fileinput.input()])
66+groups = [g.split('\n') for g in data.split('\n\n')]
77+88+99+POLYMER = groups[0][0]
1010+MAPPING = {}
1111+1212+for line in groups[1]:
1313+ a, b = line.split(' -> ')
1414+ MAPPING[a] = b
1515+1616+1717+# COUNTS maps bigrams to their counts in the underlying polymer.
1818+COUNTS = Counter()
1919+2020+2121+for i in range(len(POLYMER)-1):
2222+ COUNTS[POLYMER[i:i+2]] += 1
2323+2424+2525+for iteration in range(1, 40 + 1):
2626+ new_counts = Counter()
2727+2828+ for bigram, num in COUNTS.items():
2929+ insertion = MAPPING[bigram]
3030+3131+ new_counts[bigram[0] + insertion] += num
3232+ new_counts[insertion + bigram[1]] += num
3333+3434+ COUNTS = new_counts
3535+3636+ if iteration in (10, 40):
3737+ # Compute counts of individual letters from bigram counts.
3838+ letter_counts = Counter()
3939+4040+ for bigram, num in COUNTS.items():
4141+ letter_counts[bigram[0]] += num
4242+ letter_counts[bigram[1]] += num
4343+4444+ frequencies = zip(*letter_counts.most_common())[1]
4545+ most = (frequencies[0] + 1) // 2
4646+ least = (frequencies[-1] + 1) // 2
4747+ print "Part 1:" if iteration == 10 else "Part 2:", most - least