april_day_2026/lisp/solution3.lisp

61 lines
2.4 KiB
Common Lisp

(defun ten-to-bin (x len)
"Создает вектор бит фиксированной длины (аналог маски)."
(let ((mask (make-array len :element-type 'bit :initial-element 0)))
(loop for i from (1- len) downto 0
while (> x 0)
do (multiple-value-bind (quotient remainder) (truncate x 2)
(setf (aref mask i) remainder)
(setf x quotient)))
mask))
(defun calculate-sum (numbers-vec mask-vec)
"Считает сумму элементов вектора по маске. Использует across для векторов."
(loop for num across numbers-vec
for flag across mask-vec
when (= flag 1)
sum num))
(defun find-sum (target numbers-vec)
(declare (optimize (speed 3) (safety 0) (debug 0))
(type (simple-array fixnum (*)) numbers-vec)
(type fixnum target))
(let* ((len (length numbers-vec))
(total (1- (ash 1 len)))
(current-sum 0)
;; Массив для отслеживания текущего состояния (биты)
(bits (make-array len :element-type 'bit :initial-element 0)))
(declare (type fixnum current-sum))
(format t "Combinations: ~D~%" total)
;; Итерация по Коду Грея
(loop for i fixnum from 1 to total do
(let* ((gray-diff (logand i (- i))) ; Находим индекс изменяемого бита
(bit-idx (1- (integer-length gray-diff)))
(num (aref numbers-vec bit-idx)))
(declare (type fixnum bit-idx num))
;; Если бит был 0, прибавляем число, если 1 — вычитаем
(if (zerop (aref bits bit-idx))
(progn
(incf current-sum num)
(setf (aref bits bit-idx) 1))
(progn
(decf current-sum num)
(setf (aref bits bit-idx) 0)))
;; Проверка цели
(when (= current-sum target)
(format t "Found: ~A~%" bits)
(return-from find-sum bits))))
nil))
(defun main (args)
(let ((len (length args)))
(if (or (< len 5) (> len 30))
(progn
(format t "ER: input parameters~%")
(uiop:quit 1))
(let* ((target (parse-integer (first args)))
(numbers-vec (coerce (mapcar #'parse-integer (rest args)) 'vector)))
(find-sum target numbers-vec)))))