結果
| 問題 |
No.1105 Many Triplets
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2020-07-03 22:17:38 |
| 言語 | Common Lisp (sbcl 2.5.0) |
| 結果 |
RE
|
| 実行時間 | - |
| コード長 | 8,981 bytes |
| コンパイル時間 | 1,479 ms |
| コンパイル使用メモリ | 52,992 KB |
| 実行使用メモリ | 25,984 KB |
| 最終ジャッジ日時 | 2024-09-17 03:05:22 |
| 合計ジャッジ時間 | 3,024 ms |
|
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | RE * 3 |
| other | RE * 25 |
コンパイルメッセージ
; compiling file "/home/judge/data/code/Main.lisp" (written 17 SEP 2024 03:05:19 AM): ; file: /home/judge/data/code/Main.lisp ; in: DEFUN MAIN ; #'MOD* ; ; caught STYLE-WARNING: ; undefined function: COMMON-LISP-USER::MOD* ; #'MOD+ ; ; caught STYLE-WARNING: ; undefined function: COMMON-LISP-USER::MOD+ ; ; compilation unit finished ; Undefined functions: ; MOD* MOD+ ; caught 2 STYLE-WARNING conditions ; wrote /home/judge/data/code/Main.fasl ; compilation finished in 0:00:00.136
ソースコード
(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)
#-swank (disable-debugger) ; for CS Academy
;; BEGIN_INSERTED_CONTENTS
(declaim (inline println-sequence))
(defun println-sequence (sequence &key (out *standard-output*) (key #'identity))
(let ((init t))
(sequence:dosequence (x sequence)
(if init
(setq init nil)
(write-char #\ out))
(princ (funcall key x) out))
(terpri out)))
;;
;; Matrix multiplication over semiring
;;
;; NOTE: These funcions are slow on SBCL version earlier than 1.5.6 as the type
;; propagation of MAKE-ARRAY doesn't work. The following files are required to
;; enable the optimization.
;; version < 1.5.0: array-element-type.lisp, make-array-header.lisp
;; version < 1.5.6: make-array-header.lisp
(defun gemm! (a b c &key (op+ #'+) (op* #'*) (identity+ 0))
"Calculates C := A*B. This function destructively modifies C. (OP+, OP*) must
comprise a semiring. IDENTITY+ is the identity element w.r.t. OP+."
(declare ((simple-array * (* *)) a b c))
(dotimes (row (array-dimension a 0))
(dotimes (col (array-dimension b 1))
(let ((res identity+))
(dotimes (k (array-dimension a 1))
(setf res
(funcall op+ (funcall op* (aref a row k) (aref b k col)))))
(setf (aref c row col) res))))
c)
(declaim (inline gemm))
(defun gemm (a b &key (op+ #'+) (op* #'*) (identity+ 0))
"Calculates A*B. (OP+, OP*) must comprise a semiring. IDENTITY+ is the
identity element w.r.t. OP+."
(declare ((simple-array * (* *)) a b)
(function op+ op*))
(let ((c (make-array (list (array-dimension a 0) (array-dimension b 1))
:element-type (array-element-type a))))
(dotimes (row (array-dimension a 0))
(dotimes (col (array-dimension b 1))
(let ((res identity+))
(dotimes (k (array-dimension a 1))
(setf res
(funcall op+ res (funcall op* (aref a row k) (aref b k col)))))
(setf (aref c row col) res))))
c))
(declaim (inline matrix-power))
(defun matrix-power (base power &key (op+ #'+) (op* #'*) (identity+ 0) (identity* 1))
(declare ((simple-array * (* *)) base)
(function op+ op*)
((integer 0 #.most-positive-fixnum) power))
(let ((size (array-dimension base 0)))
(assert (= size (array-dimension base 1)))
(let ((iden (make-array (array-dimensions base)
:element-type (array-element-type base)
:initial-element identity+)))
(dotimes (i size)
(setf (aref iden i i) identity*))
(labels ((recur (p)
(declare ((integer 0 #.most-positive-fixnum) p))
(cond ((zerop p) iden)
((evenp p)
(let ((res (recur (ash p -1))))
(gemm res res :op+ op+ :op* op* :identity+ identity+)))
(t
(gemm base (recur (- p 1))
:op+ op+ :op* op* :identity+ identity+)))))
(recur power)))))
(declaim (inline gemv))
(defun gemv (a x &key (op+ #'+) (op* #'*) (identity+ 0))
"Calculates A*x for a matrix A and a vector x. (OP+, OP*) must form a
semiring. IDENTITY+ is the identity element w.r.t. OP+."
(declare ((simple-array * (* *)) a)
((simple-array * (*)) x)
(function op+ op*))
(let ((y (make-array (array-dimension a 0) :element-type (array-element-type x))))
(dotimes (i (length y))
(let ((res identity+))
(dotimes (j (length x))
(setf res
(funcall op+ res (funcall op* (aref a i j) (aref x j)))))
(setf (aref y i) res)))
y))
;;;
;;; Arithmetic operations with static modulus
;;;
;; FIXME: Currently MOD* and MOD+ doesn't apply MOD when the number of
;; parameters is one.
(defmacro define-mod-operations (divisor)
`(progn
(defun mod* (&rest args)
(reduce (lambda (x y) (mod (* x y) ,divisor)) args))
(defun mod+ (&rest args)
(reduce (lambda (x y) (mod (+ x y) ,divisor)) args))
#+sbcl
(eval-when (:compile-toplevel :load-toplevel :execute)
(locally (declare (muffle-conditions warning))
(sb-c:define-source-transform mod* (&rest args)
(if (null args)
1
(reduce (lambda (x y) `(mod (* ,x ,y) ,',divisor)) args)))
(sb-c:define-source-transform mod+ (&rest args)
(if (null args)
0
(reduce (lambda (x y) `(mod (+ ,x ,y) ,',divisor)) args)))))
(define-modify-macro incfmod (delta)
(lambda (x y) (mod (+ x y) ,divisor)))
(define-modify-macro decfmod (delta)
(lambda (x y) (mod (- x y) ,divisor)))
(define-modify-macro mulfmod (multiplier)
(lambda (x y) (mod (* x y) ,divisor)))))
(in-package :cl-user)
(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)))
(defmacro define-int-types (&rest bits)
`(progn
,@(mapcar (lambda (b) `(deftype ,(intern (format nil "UINT~A" b)) () '(unsigned-byte ,b))) bits)
,@(mapcar (lambda (b) `(deftype ,(intern (format nil "INT~A" b)) () '(signed-byte ,b))) bits)))
(define-int-types 2 4 7 8 15 16 31 32 62 63 64)
(declaim (inline println))
(defun println (obj &optional (stream *standard-output*))
(let ((*read-default-float-format* 'double-float))
(prog1 (princ obj stream) (terpri stream))))
(defconstant +mod+ 1000000007)
;;;
;;; Body
;;;
(defun main ()
(let* ((n (read))
(a1 (read))
(b1 (read))
(c1 (read))
(mat (make-array '(3 3) :element-type 'uint31 :initial-element 0))
(vec (make-array 3 :element-type 'uint31 :initial-contents (list a1 b1 c1))))
(setf (aref mat 0 0) 1
(aref mat 0 1) (- +mod+ 1)
(aref mat 1 1) 1
(aref mat 1 2) (- +mod+ 1)
(aref mat 2 0) (- +mod+ 1)
(aref mat 2 2) 1)
(let ((res (gemv (matrix-power mat (- n 1) :op+ #'mod+ :op* #'mod*)
vec
:op+ #'mod+
:op* #'mod*)))
(println-sequence res))))
#-swank (main)
;;;
;;; Test and benchmark
;;;
#+swank
(defun io-equal (in-string out-string &key (function #'main) (test #'equal))
"Passes IN-STRING to *STANDARD-INPUT*, executes FUNCTION, and returns true if
the string output to *STANDARD-OUTPUT* is equal to OUT-STRING."
(labels ((ensure-last-lf (s)
(if (eql (uiop:last-char s) #\Linefeed)
s
(uiop:strcat s uiop:+lf+))))
(funcall test
(ensure-last-lf out-string)
(with-output-to-string (out)
(let ((*standard-output* out))
(with-input-from-string (*standard-input* (ensure-last-lf in-string))
(funcall function)))))))
#+swank
(defun get-clipbrd ()
(with-output-to-string (out)
(run-program "powershell.exe" '("-Command" "Get-Clipboard") :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* out))
(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))))))
#+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)))
;; To run: (5am:run! :sample)
#+swank
(it.bese.fiveam:test :sample
(it.bese.fiveam:is
(common-lisp-user::io-equal "2
1 2 3
"
"1000000006 1000000006 2
"))
(it.bese.fiveam:is
(common-lisp-user::io-equal "3
0 0 0
"
"0 0 0
"))
(it.bese.fiveam:is
(common-lisp-user::io-equal "10
1000000000 998244353 924844033
"
"945425885 912366722 142207407
")))