Đếm các mảng thực sự độc đáo


9

Đây là phần tiếp theo để đếm mảng tạo nên các bộ duy nhất . Sự khác biệt đáng kể là định nghĩa về tính độc đáo.

Hãy xem xét một mảng Achiều dài n. Mảng chỉ chứa số nguyên dương. Ví dụ A = (1,1,2,2). Hãy để chúng tôi định nghĩa f(A)là tập hợp của tất cả các phân đoạn tiếp giáp không trống của A. Trong trường hợp này f(A) = {1,2,3,4,5,6}. Các bước để sản xuất f(A) như sau:

Các subarrays của A(1), (1), (2), (2), (1,1), (1,2), (2,2), (1,1,2), (1,2,2), (1,1,2,2). Số tiền tương ứng của họ là 1,1,2,2,2,3,4,4,5,6. Do đó, bộ bạn nhận được từ danh sách này là do {1,2,3,4,5,6}.

Chúng tôi gọi một mảng A duy nhất nếu không có mảng nào khác có Bcùng độ dài như vậy f(A) = f(B), ngoại trừ mảng bị Ađảo ngược. Ví dụ, f((1,2,3)) = f((3,2,1)) = {1,2,3,5,6}nhưng không có mảng độ dài 3nào khác tạo ra cùng một tập hợp tổng.

Bài tập

Nhiệm vụ, cho một nvà nhất định slà đếm số lượng các mảng duy nhất có độ dài đó. Bạn có thể cho rằng đó slà giữa 19. Bạn chỉ cần đếm các mảng trong đó các phần tử là một số nguyên cho trước shoặc s+1. Ví dụ, nếu s=1các mảng bạn đang đếm chỉ chứa 12. Tuy nhiên, định nghĩa về tính duy nhất là đối với bất kỳ mảng nào khác có cùng độ dài. Như một ví dụ cụ thể không phải[1, 2, 2, 2] là duy nhất vì nó cho cùng một tập hợp tổng .[1, 1, 2, 3]

Bạn nên đếm ngược lại của một mảng cũng như chính mảng đó (miễn là mảng đó không phải là một bảng màu).

Ví dụ

s = 1, câu trả lời cho n = 2,3,4,5,6,7,8,9 là:

4, 3, 3, 4, 4, 5, 5, 6

Đối với s = 1, các mảng duy nhất có độ dài 4 là

(1, 1, 1, 1)
(2, 1, 1, 2)
(2, 2, 2, 2)

s = 2, câu trả lời cho n = 2,3,4,5,6,7,8,9 là:

4, 8, 16, 32, 46, 69, 121, 177

Một ví dụ về một mảng không phải là duy nhất s = 2là:

(3, 2, 2, 3, 3, 3). 

Điều này có cùng một tập hợp tổng của cả hai: (3, 2, 2, 2, 4, 3)(3, 2, 2, 4, 2, 3).

s = 8, câu trả lời cho n = 2,3,4,5,6,7,8,9 là:

4, 8, 16, 32, 64, 120, 244, 472

Ghi bàn

Đối với một nmã nhất định , mã của bạn sẽ đưa ra câu trả lời cho tất cả các giá trị stừ 1đến 9. Điểm của bạn là giá trị cao nhất nmà điều này hoàn thành trong một phút.

Kiểm tra

Tôi sẽ cần chạy mã của bạn trên máy ubfox của mình, vì vậy vui lòng bao gồm các hướng dẫn chi tiết nhất có thể về cách biên dịch và chạy mã của bạn.

Bảng xếp hạng

  • n = 13 bởi Christian Sievers trong Haskell (42 giây)

Chúng ta được phép tiêu thụ bao nhiêu bộ nhớ?
Black Owl Kai

@BlackOwlKai Máy của tôi có 8GB nên tôi đoán 6GB có an toàn không?
Anush

Tôi nghĩ rằng số cuối cùng trong các ví dụ nên là 472 thay vì 427.
Christian Sievers

@ChristianSievers Cảm ơn bạn. Đã sửa bây giờ.
Anush

sgì Nó đại diện cho cái gì?
Gigaflop

Câu trả lời:


5

Haskell

import Control.Monad (replicateM)
import Data.List (tails)
import qualified Data.IntSet as S
import qualified Data.Map.Strict as M
import qualified Data.Vector.Unboxed as V
import Data.Vector.Unboxed.Mutable (write)
import System.Environment (getArgs)
import Control.Parallel.Strategies

orig:: Int -> Int -> M.Map S.IntSet (Maybe Int)
orig n s = M.fromListWith (\ _ _ -> Nothing) 
               [(sums l, Just $! head l) | 
                   l <- replicateM n [s, s+1],
                   l <= reverse l ]

sums :: [Int] -> S.IntSet
sums l = S.fromList [ hi-lo | (lo:r) <- tails $ scanl (+) 0 l, hi <- r ]

construct :: Int -> Int -> S.IntSet -> [Int]
construct n start set =
   setmax `seq` setmin `seq` setv `seq`
   [ weight r | r <- map (start:) $ constr (del start setlist)
                                           (V.singleton start)
                                           (n-1)
                                           (setmax - start),
                r <= reverse r ]
  where
    setlist = S.toList set
    setmin = S.findMin set
    setmax = S.findMax set
    setv = V.modify (\v -> mapM_ (\p -> write v p True) setlist)
                    (V.replicate (1+setmax) False)

    constr :: [Int] -> V.Vector Int -> Int -> Int -> [[Int]]
    constr m _ 0 _ | null m    = [[]]
                   | otherwise = []
    constr m a i x =
         [ v:r | v <- takeWhile (x-(i-1)*setmin >=) setlist,
                 V.all (V.unsafeIndex setv . (v+)) a,
                 let new = V.cons v $ V.map (v+) a,
                 r <- (constr (m \\\ new) $! new) (i-1) $! (x-v) ]

del x [] = []
del x yl@(y:ys) = if x==y then ys else if y<x then y : del x ys else yl

(\\\) = V.foldl (flip del)

weight l = if l==reverse l then 1 else 2

count n s = sum ( map value [ x | x@(_, Just _) <- M.toList $ orig n s]
                      `using` parBuffer 128 rseq )
  where 
    value (sms, Just st) = uniqueval $ construct n st sms
    uniqueval [w] = w
    uniqueval _   = 0


main = do
  [ n ] <- getArgs
  mapM_ print ( map (count (read n)) [1..9]
                    `using` parBuffer 2 r0 )

Các origchức năng tạo ra tất cả các danh sách dài nvới mục shay s+1, giúp họ nếu họ đến trước khi ngược của họ, tính sublist của họ sumsvà puts những người trong một bản đồ mà cũng nhớ phần tử đầu tiên của danh sách. Khi cùng một bộ tổng được tìm thấy nhiều lần, phần tử đầu tiên được thay thế bằng Nothing, vì vậy chúng tôi biết rằng chúng tôi không phải tìm cách khác để có được các khoản tiền này.

Các constructchức năng tìm kiếm cho các danh sách có độ dài nhất định và đưa giá trị bắt đầu có một tập hợp các khoản tiền sublist. Phần đệ quy của nó constrvề cơ bản theo cùng một logic như thế này , nhưng có một đối số bổ sung cho tổng các mục mà danh sách còn lại cần phải có. Điều này cho phép dừng sớm khi các giá trị nhỏ nhất có thể quá lớn để có được số tiền này, điều này đã mang lại sự cải thiện hiệu suất lớn. Những cải tiến lớn hơn đã đạt được bằng cách di chuyển thử nghiệm này đến một địa điểm trước đó (phiên bản 2) và bằng cách thay thế danh sách các khoản tiền hiện tại bằng một Vector(phiên bản 3 (bị hỏng) và 4 (với mức độ nghiêm ngặt bổ sung)). Phiên bản mới nhất thực hiện kiểm tra tư cách thành viên với bảng tra cứu và thêm một số nghiêm ngặt và song song hơn.

Khi constructđã tìm thấy một danh sách cung cấp cho tổng số danh sách phụ và nhỏ hơn so với đảo ngược của nó, nó có thể trả về nó, nhưng chúng tôi không thực sự quan tâm đến nó. Nó gần như là đủ để chỉ quay lại ()để chỉ ra sự tồn tại của nó, nhưng chúng ta cần biết liệu chúng ta có phải đếm nó hai lần không (vì nó không phải là một bảng màu và chúng ta sẽ không bao giờ xử lý ngược lại). Vì vậy, chúng tôi đặt 1 hoặc 2 như nó weightvào danh sách kết quả.

Hàm countđặt các phần này lại với nhau. Đối với mỗi nhóm tổng số danh sách phụ (đến từ orig) là duy nhất trong số các danh sách chỉ chứa ss+1, nó gọi value, mà gọi constructvà, thông qua uniqueval, kiểm tra nếu chỉ có một kết quả. Nếu vậy, đó là trọng số chúng ta phải tính, nếu không, tập hợp tổng không phải là duy nhất và trả về 0. Lưu ý rằng do lười biếng, constructsẽ dừng lại khi đã tìm thấy hai kết quả.

Các mainxử lý chức năng IO và vòng lặp của s1-9.

Biên dịch và chạy

Trên debian này cần các gói ghc, libghc-vector-devlibghc-parallel-dev. Lưu chương trình trong một tập tin prog.hsvà biên dịch nó với ghc -threaded -feager-blackholing -O2 -o prog prog.hs. Chạy với ./prog <n> +RTS -Nnơi <n>là chiều dài mảng mà chúng muốn đếm các mảng độc đáo.


Mã này là khá tuyệt vời (và ngắn!). Nếu bạn có thể thêm một số lời giải thích tôi chắc chắn mọi người sẽ thích hiểu những gì bạn đã làm.
Anush

Phiên bản mới của bạn không biên dịch cho tôi. Tôi nhận được bpaste.net/show/c96c4cbdc02e
Anush

Xin lỗi, xóa và dán mã lớn hơn rất khó chịu đến nỗi đôi khi tôi chỉ cần thay đổi vài dòng bằng tay. Tất nhiên tôi đã phạm sai lầm ... Đã sửa bây giờ (tôi hy vọng), và thêm một cải tiến khác, lần này chỉ với một vài phần trăm. Những thay đổi khác quan trọng hơn nhiều.
Christian Sievers
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.