Submission #8424641
Source Code Expand
;; -*- coding: utf-8 -*-
(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
;; enclose the form with VALUES to avoid being captured by LOOP macro
#\# #\> (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
(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)
;;;
;;; Modular arithmetic
;;;
;; Blankinship algorithm
;; Reference: https://topcoder.g.hatena.ne.jp/spaghetti_source/20130126/1359171466 (Japanese)
(declaim (ftype (function * (values fixnum fixnum &optional)) %ext-gcd))
(defun %ext-gcd (a b)
(declare (optimize (speed 3) (safety 0))
(fixnum a b))
(let ((y 1)
(x 0)
(u 1)
(v 0))
(declare (fixnum y x u v))
(loop (when (zerop a)
(return (values x y)))
(let ((q (floor b a)))
(decf x (the fixnum (* q u)))
(rotatef x u)
(decf y (the fixnum (* q v)))
(rotatef y v)
(decf b (the fixnum (* q a)))
(rotatef b a)))))
;; recursive version
;; (defun %ext-gcd (a b)
;; (declare (optimize (speed 3) (safety 0))
;; (fixnum a b))
;; (if (zerop b)
;; (values 1 0)
;; (multiple-value-bind (p q) (floor a b) ; a = pb + q
;; (multiple-value-bind (v u) (%ext-gcd b q)
;; (declare (fixnum u v))
;; (values u (the fixnum (- v (the fixnum (* p u)))))))))
(declaim (inline mod-inverse)
(ftype (function * (values (mod #.most-positive-fixnum) &optional)) mod-inverse))
(defun mod-inverse (a modulus)
"Solves ax ≡ 1 mod m. A and M must be coprime."
(declare (integer a)
((integer 1 #.most-positive-fixnum) modulus))
(mod (%ext-gcd a modulus) modulus))
;; Should we do this with UNWIND-PROTECT?
(defmacro with-buffered-stdout (&body body)
"Buffers all outputs to *STANDARD-OUTPUT* in BODY and flushes them to
*STANDARD-OUTPUT* after BODY has been done (without error). Note that only
BASE-CHAR is allowed."
(let ((out (gensym)))
`(let ((,out (make-string-output-stream :element-type 'base-char)))
(let ((*standard-output* ,out))
,@body)
(write-string (get-output-stream-string ,out)))))
;;;
;;; Arithmetic operations with static modulus
;;;
(defmacro define-mod-operations (divisor)
`(progn
(defun mod* (&rest args)
(reduce (lambda (x y) (mod (* x y) ,divisor)) args))
(sb-c:define-source-transform mod* (&rest args)
(if (null args)
1
(reduce (lambda (x y) `(mod (* ,x ,y) ,',divisor)) args)))
(defun mod+ (&rest args)
(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)))))
;;;
;;; Disjoint sparse table on arbitrary semigroup
;;;
;;; Reference:
;;; https://discuss.codechef.com/questions/117696/tutorial-disjoint-sparse-table
;;; http://noshi91.hatenablog.com/entry/2018/05/08/183946 (Japanese)
;;; http://drken1215.hatenablog.com/entry/2018/09/08/162600 (Japanese)
;; NOTE: This constructor is 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 make-disjoint-sparse-table (vector)
"BINOP := binary operator (comprising a semigroup)"
(declare (optimize (speed 3) (safety 0))
((simple-array uint31 (*)) vector))
(let* ((n (length vector))
(height (max 1 (integer-length (- n 1))))
(table (make-array (list height n) :element-type 'uint62)))
(dotimes (j n)
(setf (aref table 0 j) (aref vector j)))
(do ((i 1 (+ i 1)))
((>= i height))
(let* ((width/2 (ash 1 i))
(width (* width/2 2)))
(do ((j 0 (+ j width)))
((>= j n))
(let ((mid (min (+ j width/2) n)))
;; fill the first half
(setf (aref table i (- mid 1))
(aref vector (- mid 1)))
(do ((k (- mid 2) (- k 1)))
((< k j))
(setf (aref table i k)
(lcm (aref vector k) (aref table i (+ k 1)))))
(when (>= mid n)
(return))
;; fill the second half
(setf (aref table i mid)
(aref vector mid))
(let ((end (min n (+ mid width/2))))
(do ((k (+ mid 1) (+ k 1)))
((>= k end))
(setf (aref table i k)
(lcm (aref table i (- k 1)) (aref vector k)))))))))
table))
(declaim (inline dst-query))
(defun dst-query (table left right &optional identity)
"Queries the interval [LEFT, RIGHT). Returns IDENTITY for a null interval [x,
x)."
(declare ((integer 0 #.most-positive-fixnum) left right)
((simple-array * (* *)) table))
(when (>= left right)
(return-from dst-query identity))
(setq right (- right 1)) ;; change to closed interval
(if (= left right)
(aref table 0 left)
(let ((h (- (integer-length (logxor left right)) 1)))
(lcm (aref table h left) (aref table h right)))))
(declaim (inline decompose-to-cycles))
(defun decompose-to-cycles (permutation)
"Returns the list of all the cyclic permutations in a given permutation of {0,
1, ..., N-1}"
(declare (vector permutation))
(let* ((n (length permutation))
result
(visited (make-array n :element-type 'bit :initial-element 0)))
(dotimes (init n)
(when (zerop (sbit visited init))
(push (loop for x = init then (aref permutation x)
until (= (sbit visited x) 1)
collect x
do (setf (sbit visited x) 1))
result)))
result))
(declaim (ftype (function * (values fixnum &optional)) read-fixnum))
(defun read-fixnum (&optional (in *standard-input*))
(declare #.OPT)
(macrolet ((%read-byte ()
`(the (unsigned-byte 8)
#+swank (char-code (read-char in nil #\Nul))
#-swank (sb-impl::ansi-stream-read-byte in nil #.(char-code #\Nul) nil))))
(let* ((minus nil)
(result (loop (let ((byte (%read-byte)))
(cond ((<= 48 byte 57)
(return (- byte 48)))
((zerop byte) ; #\Nul
(error "Read EOF or #\Nul."))
((= byte #.(char-code #\-))
(setf minus t)))))))
(declare ((integer 0 #.most-positive-fixnum) result))
(loop
(let* ((byte (%read-byte)))
(if (<= 48 byte 57)
(setq result (+ (- byte 48)
(* 10 (the (integer 0 #.(floor most-positive-fixnum 10)) result))))
(return (if minus (- result) result))))))))
;;;
;;; Mo's algorithm
;;;
(deftype mo-integer () '(unsigned-byte 31))
(defstruct (mo (:constructor %make-mo
(lefts rights order width))
(:conc-name %mo-)
(:copier nil)
(:predicate nil))
(lefts nil :type (simple-array mo-integer (*)))
(rights nil :type (simple-array mo-integer (*)))
(order nil :type (simple-array (integer 0 #.most-positive-fixnum) (*)))
(width 0 :type (integer 0 #.most-positive-fixnum))
(index 0 :type (integer 0 #.most-positive-fixnum))
(posl 0 :type mo-integer)
(posr 0 :type mo-integer))
(defun make-mo (bucket-width lefts rights)
"TOTAL-WIDTH is the width of the interval on which the queries exist. (NOT the
number of queries.)"
(declare (optimize (speed 3) (safety 0))
((simple-array mo-integer (*)) lefts rights)
((integer 0 #.most-positive-fixnum) bucket-width)
(inline sort))
(let* ((q (length lefts))
(order (make-array q :element-type '(integer 0 #.most-positive-fixnum))))
(assert (= q (length rights)))
(dotimes (i q) (setf (aref order i) i))
(setf order (sort order
(lambda (x y)
(if (= (floor (aref lefts x) bucket-width)
(floor (aref lefts y) bucket-width))
;; Even-number [Odd-number] block is in ascending
;; [descending] order w.r.t. the right boundary.
(if (evenp (floor (aref lefts x) bucket-width))
(< (aref rights x) (aref rights y))
(> (aref rights x) (aref rights y)))
(< (aref lefts x) (aref lefts y))))))
(%make-mo lefts rights order bucket-width)))
(declaim (inline mo-get-current))
(defun mo-get-current (mo)
"Returns the original index of the current query."
(aref (%mo-order mo) (%mo-index mo)))
(declaim (inline mo-get-previous))
(defun mo-get-previous (mo)
"Returns the previous index of the current query. Returns the initial index
when no queries are processed yet."
(aref (%mo-order mo) (max 0 (- (%mo-index mo) 1))))
(declaim (inline mo-process))
(defun mo-process (mo extend shrink)
"Processes the next query. EXTEND and SHRINK take three arguments: the index
added or deleted, and both ends of the current range: [LEFT, RIGHT)"
(declare (function extend shrink))
(let* ((ord (mo-get-current mo))
(left (aref (%mo-lefts mo) ord))
(right (aref (%mo-rights mo) ord))
(posl (%mo-posl mo))
(posr (%mo-posr mo)))
(declare ((integer 0 #.most-positive-fixnum) posl posr))
(loop while (< left posl)
do (decf posl)
(funcall extend posl posl posr))
(loop while (< posr right)
do (funcall extend posr posl (+ posr 1))
(incf posr))
(loop while (< posl left)
do (funcall shrink posl (+ posl 1) posr)
(incf posl))
(loop while (< right posr)
do (decf posr)
(funcall shrink posr posl posr))
(setf (%mo-posl mo) posl
(%mo-posr mo) posr)
(incf (%mo-index mo))))
(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))))
(defconstant +mod+ 1000000007)
;;;
;;; Body
;;;
(define-mod-operations +mod+)
(defun main ()
(declare #.OPT)
(let* ((n (read))
(q (read))
(ps (make-array n :element-type 'uint31))
(ls (make-array q :element-type 'uint31))
(rs (make-array q :element-type 'uint31)))
(declare (uint31 n q))
(dotimes (i n)
(setf (aref ps i) (- (read-fixnum) 1)))
(dotimes (i q)
(let ((l (- (read-fixnum) 1))
(r (read-fixnum)))
(setf (aref ls i) l
(aref rs i) r)))
(let* ((cycles (coerce (decompose-to-cycles ps) '(simple-array list (*))))
(len (length cycles))
(perimeters (make-array len :element-type 'uint31))
(perim-invs (make-array len :element-type 'uint31))
(point-perimeters (make-array n :element-type 'uint31))
(sums (make-array len :element-type 'uint31))
(cycle-dict (make-array n :element-type 'uint31))
(res (make-array q :element-type 'uint31)))
(dotimes (i len)
(let ((sum 0)
(perimeter 0))
(declare (uint31 sum perimeter))
(dolist (v (aref cycles i))
(declare (uint31 v))
(incfmod sum v)
(incf perimeter)
(setf (aref cycle-dict v) i))
(setf (aref sums i) sum
(aref perimeters i) perimeter
(aref perim-invs i) (mod-inverse perimeter +mod+))))
(dotimes (i n)
(let ((j (aref cycle-dict i)))
(setf (aref point-perimeters i) (aref perimeters j))))
(let* ((dtable (make-disjoint-sparse-table point-perimeters))
(mo (make-mo 1000 ls rs))
(value 0)
(lcm 1)
(/lcm 1)
(original-idx 0))
(declare ((simple-array uint62 (* *)) dtable)
(uint31 value original-idx lcm /lcm))
(dotimes (_ q)
(setq original-idx (mo-get-current mo))
(mo-process
mo
(lambda (pos l r)
(let* ((cycle-idx (aref cycle-dict pos))
(sum (aref sums cycle-idx))
(new-lcm (mod (the uint62 (dst-query dtable l r 1)) +mod+))
(ratio (mod* new-lcm /lcm))
(perimeter (aref perimeters cycle-idx))
(/perimeter (aref perim-invs cycle-idx)))
(declare (uint31 cycle-idx perimeter /perimeter lcm ratio sum))
(mulfmod value ratio)
(incfmod value (mod* (the uint31 (+ perimeter sum)) (mod* new-lcm /perimeter)))
(unless (= lcm new-lcm)
(setq lcm new-lcm
/lcm (mod-inverse new-lcm +mod+)))))
(lambda (pos l r)
(let* ((cycle-idx (aref cycle-dict pos))
(sum (aref sums cycle-idx))
(new-lcm (mod (the uint62 (dst-query dtable l r 1)) +mod+))
(ratio (mod* new-lcm /lcm))
(perimeter (aref perimeters cycle-idx))
(/perimeter (aref perim-invs cycle-idx)))
(declare (uint31 cycle-idx perimeter /perimeter new-lcm ratio sum))
(mulfmod value ratio)
(incfmod value (the uint31 (- +mod+ (mod* (the uint31 (+ perimeter sum))
(mod* new-lcm /perimeter)))))
(unless (= lcm new-lcm)
(setq lcm new-lcm
/lcm (mod-inverse new-lcm +mod+))))))
(setf (aref res original-idx) value)))
(with-buffered-stdout
(map () #'println res)))))
#-swank (main)
Submission Info
| Submission Time | |
|---|---|
| Task | G - Perm Query |
| User | sansaqua |
| Language | Common Lisp (SBCL 1.1.14) |
| Score | 100 |
| Code Size | 15576 Byte |
| Status | AC |
| Exec Time | 1117 ms |
| Memory | 62312 KiB |
Judge Result
| Set Name | All | ||
|---|---|---|---|
| Score / Max Score | 100 / 100 | ||
| Status |
|
| Set Name | Test Cases |
|---|---|
| All | 00_sample_00.txt, 00_sample_01.txt, 10_small_random_00.txt, 10_small_random_01.txt, 10_small_random_02.txt, 10_small_random_03.txt, 10_small_random_04.txt, 10_small_random_05.txt, 10_small_random_06.txt, 10_small_random_07.txt, 10_small_random_08.txt, 10_small_random_09.txt, 20_random_00.txt, 20_random_01.txt, 20_random_02.txt, 20_random_03.txt, 20_random_04.txt, 20_random_05.txt, 20_random_06.txt, 20_random_07.txt, 20_random_08.txt, 20_random_09.txt, 30_random_max_00.txt, 30_random_max_01.txt, 30_random_max_02.txt, 30_random_max_03.txt, 30_random_max_04.txt, 30_random_max_05.txt, 30_random_max_06.txt, 30_random_max_07.txt, 30_random_max_08.txt, 30_random_max_09.txt, 40_long_loop_00.txt, 40_long_loop_01.txt, 40_long_loop_02.txt, 40_long_loop_03.txt, 40_long_loop_04.txt, 40_long_loop_05.txt, 40_long_loop_06.txt, 40_long_loop_07.txt, 40_long_loop_08.txt, 40_long_loop_09.txt, 50_max_query_00.txt, 50_max_query_01.txt, 50_max_query_02.txt, 50_max_query_03.txt, 50_max_query_04.txt, 50_max_query_05.txt, 50_max_query_06.txt, 50_max_query_07.txt, 50_max_query_08.txt, 50_max_query_09.txt, sample_00.txt |
| Case Name | Status | Exec Time | Memory |
|---|---|---|---|
| 00_sample_00.txt | AC | 329 ms | 62176 KiB |
| 00_sample_01.txt | AC | 329 ms | 62180 KiB |
| 10_small_random_00.txt | AC | 329 ms | 62184 KiB |
| 10_small_random_01.txt | AC | 328 ms | 62180 KiB |
| 10_small_random_02.txt | AC | 330 ms | 62176 KiB |
| 10_small_random_03.txt | AC | 329 ms | 62180 KiB |
| 10_small_random_04.txt | AC | 332 ms | 62176 KiB |
| 10_small_random_05.txt | AC | 332 ms | 62184 KiB |
| 10_small_random_06.txt | AC | 329 ms | 62176 KiB |
| 10_small_random_07.txt | AC | 331 ms | 62180 KiB |
| 10_small_random_08.txt | AC | 330 ms | 62180 KiB |
| 10_small_random_09.txt | AC | 330 ms | 62176 KiB |
| 20_random_00.txt | AC | 643 ms | 62176 KiB |
| 20_random_01.txt | AC | 965 ms | 62308 KiB |
| 20_random_02.txt | AC | 508 ms | 62308 KiB |
| 20_random_03.txt | AC | 1017 ms | 62308 KiB |
| 20_random_04.txt | AC | 810 ms | 62180 KiB |
| 20_random_05.txt | AC | 612 ms | 62176 KiB |
| 20_random_06.txt | AC | 438 ms | 62180 KiB |
| 20_random_07.txt | AC | 403 ms | 62184 KiB |
| 20_random_08.txt | AC | 811 ms | 62180 KiB |
| 20_random_09.txt | AC | 532 ms | 62184 KiB |
| 30_random_max_00.txt | AC | 1111 ms | 62308 KiB |
| 30_random_max_01.txt | AC | 1112 ms | 62308 KiB |
| 30_random_max_02.txt | AC | 1111 ms | 62308 KiB |
| 30_random_max_03.txt | AC | 1111 ms | 62304 KiB |
| 30_random_max_04.txt | AC | 1105 ms | 62312 KiB |
| 30_random_max_05.txt | AC | 1113 ms | 62308 KiB |
| 30_random_max_06.txt | AC | 1107 ms | 62304 KiB |
| 30_random_max_07.txt | AC | 1111 ms | 62308 KiB |
| 30_random_max_08.txt | AC | 1117 ms | 62308 KiB |
| 30_random_max_09.txt | AC | 1107 ms | 62308 KiB |
| 40_long_loop_00.txt | AC | 956 ms | 62308 KiB |
| 40_long_loop_01.txt | AC | 959 ms | 62304 KiB |
| 40_long_loop_02.txt | AC | 959 ms | 62312 KiB |
| 40_long_loop_03.txt | AC | 956 ms | 62304 KiB |
| 40_long_loop_04.txt | AC | 954 ms | 62304 KiB |
| 40_long_loop_05.txt | AC | 957 ms | 62304 KiB |
| 40_long_loop_06.txt | AC | 957 ms | 62308 KiB |
| 40_long_loop_07.txt | AC | 956 ms | 62312 KiB |
| 40_long_loop_08.txt | AC | 959 ms | 62308 KiB |
| 40_long_loop_09.txt | AC | 956 ms | 62308 KiB |
| 50_max_query_00.txt | AC | 574 ms | 62308 KiB |
| 50_max_query_01.txt | AC | 575 ms | 62308 KiB |
| 50_max_query_02.txt | AC | 575 ms | 62308 KiB |
| 50_max_query_03.txt | AC | 574 ms | 62304 KiB |
| 50_max_query_04.txt | AC | 576 ms | 62312 KiB |
| 50_max_query_05.txt | AC | 575 ms | 62304 KiB |
| 50_max_query_06.txt | AC | 575 ms | 62304 KiB |
| 50_max_query_07.txt | AC | 574 ms | 62312 KiB |
| 50_max_query_08.txt | AC | 574 ms | 62304 KiB |
| 50_max_query_09.txt | AC | 575 ms | 62312 KiB |
| sample_00.txt | AC | 329 ms | 62184 KiB |