ACM国際大学対抗プログラミングコンテスト(E)

{-
  http://www.acm-japan.org/past-icpc/domestic2006/contest/all_ja.html#section_E
  2007.06.15
  nisikawa
-}
import Text.ParserCombinators.Parsec

data Genom = S String | G Integer [Genom] deriving Show

exec :: String -> Integer -> Char
exec line idx = exec' idx $ run line
  where exec' idx [] = '0' 
        exec' idx (x:xs) = let l = dataLength x in if l > idx then at idx l x else exec' (idx - l) xs
        dataLength (S s) = toInteger $ length s
        dataLength (G n gs) = n * (sum $ map dataLength gs) 
        at idx len (S s) = let i = idx `mod` len in s !! (fromInteger i)
        at idx len (G n gs) = exec' idx $ concat $ replicate (fromInteger n) gs

run line = case (parse genoms "" line) of
              Left e   -> error $ show e
              Right gs -> gs

genoms = do
   g  <- genom
   gs <- try genoms <|> return []
   return $ g:gs

genom = try parseS <|> parseG

parseS = do
   s <- many1 $ oneOf "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
   return $ S s 

parseG = do
   i  <- many1 digit
   gs <- try (parseS >>= \s -> return [s]) <|> paren
   return $ G (read i) gs

paren = do
   char '('
   gs <- genoms
   char ')'
   return gs