Permalink
Cannot retrieve contributors at this time
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
61 lines (61 sloc)
2.6 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;;; Google Code Jam 2020, Round 1C, Problem 2: Overrandomized | |
;;; | |
;;; See https://blog.simon.leinen.ch/2020/05/google-code-jam-2020-in-lispround-1c.html | |
;;; | |
;;; This code is supposed to solve the problem for all inputs. It | |
;;; always ignores the random queries (Qi), because they aren't | |
;;; defined in the "difficult" input set. | |
;;; | |
;;; The idea is as follows: | |
;;; | |
;;; First we find out which symbol stands for the digit 0 (zero). | |
;;; Since there are no leading zeroes, and the random numbers are | |
;;; never 0, we know that the first symbols can never represent zero. | |
;;; So we look for the symbol that never appears as a first digit. | |
;;; | |
;;; Next, we look at the counts of how often each of the remaining | |
;;; nine symbols appears as the first digit. The most frequently | |
;;; occurring symbol certainly stands for the digit 1, the next most | |
;;; for digit 2, and so on. | |
;;; | |
;;; This sounds stupid, but it works reliably enough when the input | |
;;; set is as large as 10000 trials. | |
;;; | |
(labels | |
((i2c (i) (code-char (+ i #.(char-code #\A)))) | |
(c2i (c) (- (char-code c) #.(char-code #\A)))) | |
(dotimes (caseno (read)) | |
(format t "Case #~D: " (+ caseno 1)) | |
(let ((u (read)) | |
(seen 0) | |
(d1-counters (make-array (list 26) :initial-element 0))) | |
(dotimes (i 10000) | |
;; Note: Initially, I simply read QI and RI as follows: | |
;; | |
;; (let ((qi (read)) (ri (read-line))) ...) | |
;; | |
;; However, that caused a "RE" (runtime error) somewhere when | |
;; submitted to the Code Jam platform. Splitting the lines | |
;; explicitly as below evades that issue. | |
;; | |
(let ((line (read-line))) | |
(let ((space-pos (position #\Space line))) | |
(assert space-pos) | |
(assert (not (zerop space-pos))) | |
(let ((qi (parse-integer line :start 0 :end space-pos)) | |
(ri (subseq line (1+ space-pos)))) | |
(assert (or (= qi -1) (<= 1 qi (- (expt 10 u) 1)))) | |
(assert (<= 1 (length ri) u)) | |
(assert (every #'alpha-char-p ri)) | |
(assert (every #'upper-case-p ri)) | |
(incf (aref d1-counters (c2i (char ri 0)))) | |
(dotimes (k (length ri)) | |
(setf seen (logior seen (ash 1 (c2i (char ri k)))))))))) | |
(let ((zero (dotimes (i 26 0) | |
(when (and (logbitp i seen) (zerop (aref d1-counters i))) | |
(return i))))) | |
(write-char (i2c zero)) | |
(let ((sorted-counters (sort (copy-seq d1-counters) #'>))) | |
(dotimes (i 9) | |
(write-char (i2c (position (aref sorted-counters i) d1-counters))))))) | |
(terpri))) |