(in-package :cl-user)
(eval-when (:compile-toplevel :load-toplevel :execute)
  (sb-int:defconstant-eqx opt
    #+swank '(optimize (speed 3) (safety 2))
    #-swank '(optimize (speed 3) (safety 0) (debug 0))
    #'equal)
  #+swank (ql:quickload '(:cl-debug-print :fiveam) :silent t)
  #-swank (set-dispatch-macro-character
           #\# #\> (lambda (s c p) (declare (ignore c p)) `(values ,(read s nil nil t)))))
#+swank (cl-syntax:use-syntax cl-debug-print:debug-print-syntax)

(macrolet ((def-int (b)
             `(progn (deftype ,(intern (format nil "UINT~A" b)) () '(unsigned-byte ,b))
                     (deftype ,(intern (format nil "INT~A" b)) () '(signed-byte ,b))))
           (defs (&rest bits) `(progn ,@(mapcar (lambda (b) `(def-int ,b)) bits))))
  (defs 2 4 7 8 15 16 31 32 62 63 64))

(defconstant +mod+ 1000000007)

(defmacro dbg (&rest forms)
  #+swank (if (= (length forms) 1)
              `(format *error-output* "~A => ~A~%" ',(car forms) ,(car forms))
              `(format *error-output* "~A => ~A~%" ',forms `(,,@forms)))
  #-swank (declare (ignore forms)))

(declaim (inline println))
(defun println (obj &optional (stream *standard-output*))
  (let ((*read-default-float-format* 'double-float))
    (prog1 (princ obj stream) (terpri stream))))

;; BEGIN_INSERTED_CONTENTS
(defpackage :cp/println-matrix
  (:use :cl)
  (:export #:println-matrix))
(in-package :cp/println-matrix)

(declaim (inline println-matrix))
(defun println-matrix (array &key (separator #\ ) (key #'identity) (writer #'write) (row-start 0) row-end (col-start 0) col-end)
  "Prints a 2-dimensional array."
  (declare ((array * (* *)) array)
           ((integer 0 #.most-positive-fixnum) row-start col-start))
  (let ((row-end (or row-end (array-dimension array 0)))
        (col-end (or col-end (array-dimension array 1))))
    (declare ((integer 0 #.most-positive-fixnum) row-end col-end))
    (loop for i from row-start below row-end
          do (loop for j from col-start below col-end
                   unless (= j col-start)
                   do (princ separator)
                   do (funcall writer (funcall key (aref array i j))))
             (terpri))))

(defpackage :cp/integer-expression
  (:use :cl)
  (:export #:integer-reverse #:palindrome-integer-p #:integer-concat))
(in-package :cp/integer-expression)

(declaim (inline integer-reverse))
(defun integer-reverse (x &optional (base 10))
  "Returns the integer displayed in reversed order of X."
  (declare (integer x))
  (let ((sign (signum x))
        (x (abs x))
        (res 0))
    (loop (when (zerop x)
            (return (* res sign)))
          (multiple-value-bind (quot rem) (floor x base)
            (setq res (+ (* base res) rem)
                  x quot)))))

(declaim (inline palindrome-integer-p))
(defun palindrome-integer-p (x &optional (base 10))
  "Returns true iff X is palindromically displayed."
  (= x (integer-reverse x base)))

(declaim (inline integer-concat))
(defun integer-concat (x y &optional (base 10))
  (declare ((integer 0 #.most-positive-fixnum) x y))
  (let ((coef 1))
    (declare ((integer 0 #.most-positive-fixnum) base))
    (loop until (> coef y)
          do (setq coef (* coef base)))
    (+ (* x coef) y)))

;; BEGIN_USE_PACKAGE
(eval-when (:compile-toplevel :load-toplevel :execute)
  (use-package :cp/integer-expression :cl-user))
(eval-when (:compile-toplevel :load-toplevel :execute)
  (use-package :cp/println-matrix :cl-user))
(in-package :cl-user)

;;;
;;; Body
;;;

;; 行: N
;; 列: 質問
(defun test (n)
  (let ((mat (make-array (list n n) :element-type 'bit :initial-element 0)))
    (dotimes (i n)
      (dotimes (j n)
        (when (or (and (<= (+ j 1) (+ i 1))
                       (string<= (write-to-string (+ j 1))
                                 (write-to-string (+ i 1))))
                  (and (> (+ j 1) (+ i 1))
                       (string> (write-to-string (+ j 1))
                                (write-to-string (+ i 1)))))
          (setf (aref mat i j) 1))))
    (println-matrix mat :separator "")))

(defconstant +max-width+ 10)
(defun main ()
  (let* ((count 0))
    (labels ((query (x)
               (when (= count 64) (loop))
               (when (zerop x) (loop))
               (incf count)
               (format t "? ~D~%" x)
               (ecase (read) (y t) (n nil))))
      (let* ((ms-digit (sb-int:named-let bisect ((ok 0) (ng 10))
                         (if (<= (- ng ok) 1)
                             ok
                             (let ((mid (ash (+ ok ng) -1)))
                               (if (query mid)
                                   (bisect mid ng)
                                   (bisect ok mid))))))
             (exp (sb-int:named-let bisect ((ok 0) (ng (+ +max-width+ 1)))
                    (if (<= (- ng ok) 1)
                        ok
                        (let ((mid (ash (+ ok ng) -1)))
                          (if (query (expt 10 mid))
                              (bisect mid ng)
                              (bisect ok mid))))))
             (res (cond ((and (= ms-digit 1) (= exp +max-width+)) ;; 10, 100, ...
                         (sb-int:named-let bisect ((ng 0) (ok 10))
                           (if (<= (- ok ng) 1)
                               (expt 10 ok)
                               (let ((mid (ash (+ ng ok) -1)))
                                 (if (query (- (expt 10 (+ mid 1)) 1))
                                     (bisect ng mid)
                                     (bisect mid ok))))))
                        ((and (= ms-digit 9) (= exp 0)) ;; 2, 3, ..., 9
                         (sb-int:named-let bisect ((ng 0) (ok 10))
                           (if (<= (- ok ng) 1)
                               ok
                               (let ((mid (ash (+ ng ok) -1)))
                                 (if (query (* 10 mid))
                                     (bisect ng mid)
                                     (bisect mid ok))))))
                        ((and (= ms-digit 9) (= exp +max-width+)) 1)
                        (t (sb-int:named-let bisect ((ng (- (* ms-digit (expt 10 exp)) 1))
                                                     (ok (* (+ ms-digit 1) (expt 10 exp))))
                             (dbg ng ok)
                             (if (<= (- ok ng) 1)
                                 ok
                                 (let ((mid (ash (+ ng ok) -1)))
                                   (if (query (* 10 mid))
                                       (bisect ng mid)
                                       (bisect mid ok)))))))))
        (format t "! ~D~%" res)))))

#-swank (main)

;;;
;;; Test and benchmark
;;;

#+swank
(defun get-clipbrd ()
  (with-output-to-string (out)
    #+os-windows (run-program "powershell.exe" '("-Command" "Get-Clipboard") :output out :search t)
    #+os-unix (run-program "xsel" '("-b" "-o") :output out :search t)))

#+swank (defparameter *this-pathname* (uiop:current-lisp-file-pathname))
#+swank (defparameter *dat-pathname* (uiop:merge-pathnames* "test.dat" *this-pathname*))

#+swank
(defun run (&optional thing (out *standard-output*))
  "THING := null | string | symbol | pathname

null: run #'MAIN using the text on clipboard as input.
string: run #'MAIN using the string as input.
symbol: alias of FIVEAM:RUN!.
pathname: run #'MAIN using the text file as input."
  (let* ((*standard-output* (or out (make-string-output-stream)))
         (res (etypecase thing
                (null
                 (with-input-from-string (*standard-input* (delete #\Return (get-clipbrd)))
                   (main)))
                (string
                 (with-input-from-string (*standard-input* (delete #\Return thing))
                   (main)))
                (symbol (5am:run! thing))
                (pathname
                 (with-open-file (*standard-input* thing)
                   (main))))))
    (if out res (get-output-stream-string *standard-output*))))

#+swank
(defun gen-dat ()
  (uiop:with-output-file (out *dat-pathname* :if-exists :supersede)
    (format out "")))

#+swank
(defun bench (&optional (out (make-broadcast-stream)))
  (time (run *dat-pathname* out)))

#-swank
(eval-when (:compile-toplevel)
  (when (and (boundp 'sb-c::*compiler-warning-count*)
             (> sb-c::*compiler-warning-count* 0))
    (sb-ext:quit :unix-status 1)))

;; To run: (5am:run! :sample)
#+swank
(it.bese.fiveam:test :sample)


Measured memory_bytes: 24988