import Control.Monad import Control.Monad.ST import Data.Array.Unboxed import Data.Array.ST import Data.Maybe import Data.Bits import Text.Printf type Board = UArray (Int,Int) Bool unhex :: Char -> [Bool] unhex c = fromJust (lookup c table) where table = zip (['0'..'9'] ++ ['A'..'F']) [[testBit i j | j <- [3,2..0]] | i <- [(0::Int) .. 15]] mkBoard :: Int -> Int -> [[Bool]] -> Board mkBoard m n rows = array ((1,1),(m,n)) $ do (i,row) <- zip [1..] rows (j,v) <- zip [1..] row return ((i,j),v) solve :: Int -> Int -> Board -> [(Int,Int)] solve m n board = runST (thaw table >>= solve' m n) where table = mkTable board mkTable :: Board -> Array (Int,Int) Int mkTable board = table where table = array b [(p, f p) | p <- range b] b@(_, (m,n)) = bounds board f (i,j) | i==m || j==n = 1 | board!(i,j) == board!(i+1,j) = 1 | board!(i,j) == board!(i,j+1) = 1 | board!(i,j) /= board!(i+1,j+1) = 1 | otherwise = 1 + minimum [table!(i+1,j), table!(i,j+1), table!(i+1,j+1)] solve' :: Int -> Int -> STUArray s (Int,Int) Int -> ST s [(Int, Int)] solve' m n table = do let o = min m n forM' [o,o-1..1] $ \size -> do ps <- forM' [1..m-size+1] $ \i -> do forM' [1..n-size+1] $ \j -> do x <- readArray table (i,j) if x < size then return [] else do forM_ [max 1 (i-size) .. i+size-1] $ \i1 -> forM_ [max 1 (j-size) .. j+size-1] $ \j1 -> if i<=i1 && j<=j1 then writeArray table (i1,j1) 0 else do y <- readArray table (i1,j1) writeArray table (i1,j1) $ min y (max (i-i1) (j-j1)) return [(i,j)] return [(size, l) | let l = length ps, l > 0] forM' :: Monad m => [a] -> (a -> m [b]) -> m [b] forM' xs f = liftM concat $ mapM f xs main :: IO () main = do t <- readLn forM_ [(1::Int)..t] $ \x -> do [m,n] <- liftM (map read . words) getLine rows <- forM [1..m] $ \_ -> do row <- getLine return $ concatMap unhex row let board = mkBoard m n rows ans = solve m n board printf "Case #%d: %d\n" x (length ans) forM_ ans $ \(size, cnt) -> printf "%d %d\n" size cnt