Problem:
ブロックの三角形

図a のように積まれたブロックに対し、以下の並べ替え操作を繰り返す。

一番下のブロック全て（図a 中の白のブロック）を右端に新しく積み上げる（残りのブロックは自動的に１段下に落ち、図b のようになる）。

ブロックの間に隙間ができたら、左に詰めて隙間をなくす（図 b から図c のようになる）。

1 以上の整数 k に対して、k×(k＋1)/2 で表される数 (例:1, 3, 6, 10, ...)を三角数という。ブロックの総数が三角数の場合、上記の並べ替えを繰り返すと、左端の高さが1 で右に向かって１つずつ高くなっていくような三角形になると予想されている（図d は総数が15 個の場合）。

ブロックの最初の並びが与えられたとき、あらかじめ決められた回数以下の操作で、上で説明したようなブロックの三角形ができるとき、三角形が得られるまでの最小の操作回数を出力するプログラムを作成してください。

入力

入力は複数のデータセットからなる。入力の終わりはゼロ１つの行で示される。各データセットは以下の形式で与えられる。

N
b1 b2 ... bN

各データセットは２行であり、ブロックの最初の並びを表す。N (1 ≤ N ≤ 100)は、一番下の段にあるブロックの数を示す。bi(1 ≤ bi ≤ 10000) は左から i 番目の位置に積まれているブロックの数を示す。bi と bi+1 は１つの空白で区切られている。ブロックの総数は 3 以上である。

データセットの数は 20 を超えない。

出力

データセットごとに、三角形ができるまでに行った並べ替え操作の回数を１行に出力する。ただし、三角形が作れない場合や、操作回数が 10000 回を超える場合は -1 を出力する。

入力例

6
1 4 1 3 2 4
5
1 2 3 4 5
10
1 1 1 1 1 1 1 1 1 1
9
1 1 1 1 1 1 1 1 1
12
1 4 1 3 2 4 3 3 2 1 2 2
1
5050
3
10000 10000 100
0

出力例

24
0
10
-1
48
5049
-1

最初のデータセットが、図に示した場合に対応する。

４つ目のデータセットが、ブロックの総数が三角数でないため、三角形が作れない場合に対応する。

最後のデータセットが、ブロックの総数は三角数だが、操作回数が 10000 回を超える場合に対応する。

Solution in Haskell (judge verdict: Accepted)

import Control.Applicative ((<$>))
import Control.Monad (unless)
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B
import Data.List (unfoldr)
import Data.Char (isSpace)

main :: IO ()
main = do
  n <- readLn
  unless (n == 0) $ do
    solve n <$> readil B.readInt <$> B.getLine >>= print
    main
    
solve :: Int -> [Int] -> Int
solve n xs = cnt 0 (n, xs)
  where f (c, as) = foldr g (1, [c]) as
          where g e (d, bs) | e == 1 = (d, bs)
                            | otherwise = (d+1, (e-1):bs)
        cnt i (c, as) | i > 10000 = (-1)
                      | isTriangle as = i
                      | otherwise = cnt (i+1) (f (c, as))

isTriangle :: [Int] -> Bool
isTriangle xs = head xs == 1 && all f (zip xs (tail xs))
  where f (a, b) = a + 1 == b
        
readil :: Integral a =>  (ByteString -> Maybe (a, ByteString)) -> ByteString -> [a]
readil f = unfoldr g
  where
    g s = do
      (n, s') <- f s
      return (n, B.dropWhile isSpace s')