Submission #5607338


Source Code Expand

;; -*- coding: utf-8 -*-
(eval-when (:compile-toplevel :load-toplevel :execute)
  (defparameter OPT
    #+swank '(optimize (speed 3) (safety 2))
    #-swank '(optimize (speed 3) (safety 0) (debug 0)))
  #+swank (progn (ql:quickload '(:cl-debug-print :fiveam))
                 (shadow :run)
                 (use-package :fiveam)))
#+swank (cl-syntax:use-syntax cl-debug-print:debug-print-syntax)

;; BEGIN_INSERTED_CONTENTS
;;;
;;; Binomial coefficient with mod
;;; build: O(n)
;;; query: O(1)
;;;

(defconstant +binom-size+ 510000)
(defconstant +binom-mod+ #.(+ (expt 10 9) 7))

(declaim ((simple-array (unsigned-byte 32) (*)) *fact* *fact-inv* *inv*))
(defparameter *fact* (make-array +binom-size+ :element-type '(unsigned-byte 32)))
(defparameter *fact-inv* (make-array +binom-size+ :element-type '(unsigned-byte 32)))
(defparameter *inv* (make-array +binom-size+ :element-type '(unsigned-byte 32)))

(defun initialize-binom ()
  (setf (aref *fact* 0) 1
        (aref *fact* 1) 1
        (aref *fact-inv* 0) 1
        (aref *fact-inv* 1) 1
        (aref *inv* 1) 1)
  (loop for i from 2 below +binom-size+
        do (setf (aref *fact* i) (mod (* i (aref *fact* (- i 1))) +binom-mod+)
                 (aref *inv* i) (mod (- (* (aref *inv* (rem +binom-mod+ i))
                                           (floor +binom-mod+ i)))
                                     +binom-mod+)
                 (aref *fact-inv* i) (mod (* (aref *inv* i)
                                             (aref *fact-inv* (- i 1)))
                                          +binom-mod+))))

(initialize-binom)

(declaim (inline binom))
(defun binom (n k)
  "Returns nCk."
  (if (or (< n k) (< n 0) (< k 0))
      0
      (mod (* (aref *fact* n)
              (mod (* (aref *fact-inv* k) (aref *fact-inv* (- n k))) +binom-mod+))
           +binom-mod+)))

(defun multinomial (&rest ks)
  "Returns the multinomial coefficient K!/k_1!k_2!...k_n! for K = k_1 + k_2 +
... + k_n. K must be equal or smaller than MOST-POSITIVE-FIXNUM. (multinomial)
returns 1."
  (let ((sum 0)
        (result 1))
    (declare ((integer 0 #.most-positive-fixnum) result sum))
    (dolist (k ks)
      (incf sum k)
      (setq result
            (mod (* result (aref *fact-inv* k)) +binom-mod+)))
    (mod (* result (aref *fact* sum)) +binom-mod+)))

(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 mod* (&rest args)
  (reduce (lambda (x y) (mod (* x y) +mod+)) args))

(define-compiler-macro mod* (&rest args)
  (if (null args)
      1
      (reduce (lambda (x y) `(mod (* ,x ,y) +mod+)) args)))

(defun mod+ (&rest args)
  (reduce (lambda (x y) (mod (+ x y) +mod+)) args))

(define-compiler-macro mod+ (&rest args)
  (if (null args)
      0
      (reduce (lambda (x y) `(mod (+ ,x ,y) +mod+)) args)))

(define-modify-macro incfmod (delta divisor)
  (lambda (x y divisor) (mod (+ x y) divisor)))

(defun main ()
  (let* ((n (read))
         (m (read))
         (k (read)))
    (let ((res (mod+ (mod* m m (binom (- (* n m) 2) (- k 2))
                           (loop with res = 0
                                 for i from 1 to (- n 1)
                                 do (incfmod res (mod* i (- n i)) +mod+)
                                 finally (return res)))
                     (mod* n n (binom (- (* n m) 2) (- k 2))
                           (loop with res = 0
                                 for i from 1 to (- m 1)
                                 do (incfmod res (mod* i (- m i)) +mod+)
                                 finally (return res))))))
      (println res))))

#-swank(main)


;; For Test
#+swank
(defun io-equal (in-string out-string &optional (func #'main))
  (labels ((ensure-last-lf (s)
             (if (and (> (length s) 0)
                      (eql (char s (- (length s) 1)) #\Linefeed))
                 s
                 (uiop:strcat s uiop:+lf+))))
    (equal (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 func)))))))

#+swank
(defun get-clipbrd ()
  (with-output-to-string (out)
    (run-program "C:/msys64/usr/bin/cat.exe" '("/dev/clipboard") :output out)))

#+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*))
  (let ((*standard-output* out))
    (etypecase thing
      (null ; Runs #'MAIN with the string on clipboard
       (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 ; Runs #'MAIN with the string in a text file
       (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 2 2
"
    "8
"))
  (it.bese.fiveam:is
   (common-lisp-user::io-equal "4 5 4
"
    "87210
"))
  (it.bese.fiveam:is
   (common-lisp-user::io-equal "100 100 5000
"
    "817260251
")))

Submission Info

Submission Time
Task E - Cell Distance
User sansaqua
Language Common Lisp (SBCL 1.1.14)
Score 500
Code Size 6370 Byte
Status AC
Exec Time 268 ms
Memory 38248 KiB

Judge Result

Set Name Sample All
Score / Max Score 0 / 0 500 / 500
Status AC
AC × 25
Set Name Test Cases
Sample
All 01.txt, 02.txt, 03.txt, 04.txt, 05.txt, 06.txt, 07.txt, 08.txt, 09.txt, 10.txt, 11.txt, 12.txt, 13.txt, 14.txt, 15.txt, 16.txt, 17.txt, 18.txt, 19.txt, 20.txt, 21.txt, 22.txt, s1.txt, s2.txt, s3.txt
Case Name Status Exec Time Memory
01.txt AC 268 ms 38248 KiB
02.txt AC 132 ms 27108 KiB
03.txt AC 130 ms 27104 KiB
04.txt AC 129 ms 27108 KiB
05.txt AC 131 ms 27108 KiB
06.txt AC 131 ms 27104 KiB
07.txt AC 130 ms 27108 KiB
08.txt AC 137 ms 27108 KiB
09.txt AC 129 ms 27108 KiB
10.txt AC 128 ms 27108 KiB
11.txt AC 129 ms 27108 KiB
12.txt AC 130 ms 27112 KiB
13.txt AC 130 ms 27104 KiB
14.txt AC 131 ms 27112 KiB
15.txt AC 131 ms 27112 KiB
16.txt AC 131 ms 27104 KiB
17.txt AC 131 ms 27108 KiB
18.txt AC 131 ms 27108 KiB
19.txt AC 130 ms 27104 KiB
20.txt AC 139 ms 27112 KiB
21.txt AC 140 ms 27108 KiB
22.txt AC 130 ms 27108 KiB
s1.txt AC 130 ms 27104 KiB
s2.txt AC 130 ms 27108 KiB
s3.txt AC 130 ms 27108 KiB