정말 독특한 배열 수


9

이것은 고유 한 세트를 만드는 Count 배열에 대한 후속 조치 입니다. 중요한 차이점은 고유성의 정의입니다.

Alength 배열 을 고려하십시오 n. 배열은 양의 정수만 포함합니다. 예를 들면 A = (1,1,2,2). f(A)비어 있지 않은 연속 된 모든 하위 배열의 합 집합을 정의합시다 A. 이 경우 f(A) = {1,2,3,4,5,6}. 생산 단계 f(A) 는 다음과 같습니다.

의 하위 배열은 A입니다 (1), (1), (2), (2), (1,1), (1,2), (2,2), (1,1,2), (1,2,2), (1,1,2,2). 각각의 합계는 1,1,2,2,2,3,4,4,5,6입니다. 따라서이 목록에서 얻는 세트는 {1,2,3,4,5,6}입니다.

같은 길이의 다른 배열이없는 경우 배열을 뒤집는 것을 제외하고 는 A 고유 한 배열을 호출합니다 . 예를 들어, 동일한 합계 세트를 생성하는 다른 길이 배열은 없습니다 .Bf(A) = f(B)Af((1,2,3)) = f((3,2,1)) = {1,2,3,5,6}3

직무

작업은 주어진 위해 n그리고 s그 길이의 독특한 배열의 수를 계산하는 것입니다. 과 s사이에 있다고 가정 할 수 있습니다 . 요소가 지정된 정수 또는 배열 인 배열 만 계산하면 됩니다. 예를 들어 계산하려는 배열에 and 만 포함되어 있으면 . 그러나 고유성의 정의는 동일한 길이의 다른 배열과 관련이 있습니다. 구체적인 예로서 이다 되지 는 같은 금액의 동일한 세트를 제공 같은 고유 .19ss+1s=112[1, 2, 2, 2][1, 1, 2, 3]

배열이 물론 회문이 아닌 한 배열 자체와 배열의 반대 방향을 세어야합니다.

s = 1n = 2,3,4,5,6,7,8,9에 대한 답변은 다음과 같습니다.

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

의 경우 s = 1길이가 4 인 고유 한 배열은

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

s = 2n = 2,3,4,5,6,7,8,9에 대한 답변은 다음과 같습니다.

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

고유하지 않은 배열의 예 s = 2는 다음 과 같습니다.

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

이것은 모두 같은 금액의 동일한 세트를 가지고 (3, 2, 2, 2, 4, 3)(3, 2, 2, 4, 2, 3).

s = 8n = 2,3,4,5,6,7,8,9에 대한 답변은 다음과 같습니다.

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

점수

주어진 n코드의 경우 sfrom에서 모든 값에 대한 답변을 출력해야 1합니다 9. n1 분 안에 완료되는 최고 점수입니다 .

테스팅

우분투 컴퓨터에서 코드를 실행해야하므로 코드를 컴파일하고 실행하는 방법에 대해 가능한 한 자세한 지침을 포함하십시오.

리더 보드

  • Haskell의 Christian Sievers의 n = 13 (42 초)

얼마나 많은 메모리를 사용할 수 있습니까?
Black Owl Kai

@BlackOwlKai 내 컴퓨터에는 8GB가 있으므로 6GB가 안전하다고 생각하십니까?
Anush

예에서 마지막 숫자는 427 대신 472 여야한다고 생각합니다.
Christian Sievers

@ChristianSievers 감사합니다. 지금 수정했습니다.
Anush

무엇입니까 s? 그것은 무엇을 상징합니까?
Gigaflop

답변:


5

하스켈

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 )

orig함수 n는 항목 이 포함 된 모든 길이의 목록을 작성 s하거나 s+1, sums목록의 첫 번째 요소를 기억하는 하위 목록을 계산하고 하위 목록을 계산 하여 맵에 넣습니다. 동일한 합계가 두 번 이상 발견되면 첫 번째 요소가로 바뀌 Nothing므로 이러한 합계를 얻는 다른 방법을 찾을 필요가 없습니다.

construct함수는 주어진 서브리스트 합계 세트를 가진 주어진 길이와 주어진 시작 값의리스트를 검색합니다. 재귀 부분 constr은 본질적으로 this 와 동일한 논리를 따르지만 나머지 목록 항목에 필요한 합계를 제공하는 추가 인수가 있습니다. 가장 작은 값이라도이 합계를 얻기에 너무 큰 경우 조기에 중지 할 수있어 성능이 크게 향상됩니다. 이 테스트를 이전 위치 (버전 2)로 옮기고 현재 합계 목록을 Vector(버전 3 (파손) 및 4 (추가 엄격함)) 로 바꾸면 더 큰 개선이 이루어 졌습니다. 최신 버전은 조회 테이블을 사용하여 멤버쉽 테스트를 설정하고 엄격 성과 병렬화를 추가합니다.

construct하위 목록의 합계를 제공하고 그 반대보다 작은 목록을 발견했다, 그것을 반환 할 수 있지만, 우리는 정말 관심이 없습니다. 그것 ()의 존재를 나타 내기 위해 돌아 오는 것만으로도 충분 하지만, 우리는 그것을 회문이 아니기 때문에 우리는 그것을 두 번 세어야하는지 알아야합니다. 따라서 weight결과 목록에 1 또는 2를 넣습니다.

이 기능 count은이 부분들을 하나로 묶습니다. 하위 목록 합계의 각 세트 (으 orig)만을 포함하는리스트 중에서 독특 해당 s하고 s+1, 그 통화는 value, 어느 전화 construct를 통해, 그리고 uniqueval단지 하나 개의 결과가 있는지 확인. 그렇다면 계산해야 할 가중치입니다. 그렇지 않으면 합계 집합이 고유하지 않고 0이 반환됩니다. 게으름으로 인해 construct두 가지 결과가 발견되면 중지됩니다.

main함수는 IO와 s1에서 9까지 의 루프를 처리합니다 .

컴파일과 실행

데비안이 패키지를 필요 ghc, libghc-vector-devlibghc-parallel-dev. 프로그램을 파일로 저장 prog.hs하고로 컴파일하십시오 ghc -threaded -feager-blackholing -O2 -o prog prog.hs. ./prog <n> +RTS -Nwhere <n>로 실행 하여 고유 한 배열을 계산할 배열 길이입니다.


이 코드는 매우 놀랍습니다 (짧습니다). 설명을 추가 할 수 있다면 사람들이 당신이 한 일을 이해하고 싶어 할 것입니다.
Anush

새 버전이 컴파일되지 않습니다. 내가 얻을 bpaste.net/show/c96c4cbdc02e
Anush

더 큰 코드를 삭제하고 붙여 넣기가 너무 불편하여 때로는 몇 줄씩 손으로 변경하기도합니다. 물론 나는 실수를했다 ... 지금 고쳐라 (나는 바란다). 다른 변화는 훨씬 더 중요했습니다.
Christian Sievers
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.