Problem:
入力候補

携帯電話には、メールなどの文章を効率良く入力するために入力候補を表示する機能が搭載されています。これは、使われる頻度が高い単語を記録しておき、入力された文字を頭文字に持つ単語を入力候補として提示するものです。例えば、普段”computer”という単語を多く入力しているなら、”c”と入力するだけで候補として”computer”が提示されます。このような機能の基本部分を作成してみましょう。

文章、文字を入力とし、その文字を頭文字に持つ単語を出現数の順に出力するプログラムを作成してください。ただし、出現数が同じ単語が複数ある場合は、辞書式順序で出力します。出力する単語は最大5つまでとします。該当する単語が存在しない場合は”NA”と出力してください。

入力

複数のデータセットが与えられます。入力の終わりはゼロひとつで表されます。各データセットは以下の形式で与えられます。

n
line1
line2
:
linen
k

1行目に文章の行数 n (1 ≤ n ≤ 10) が与えられます。続く n 行に文章が与えられます。文章は半角英小文字と半角空白からなり、１行の文字数は1文字以上1024文字以下とします。空白によって区切られる単語は1文字以上20文字以下です。

続く行に頭文字 k が半角英字で与えられます。

データセットの数は 100 を超えません。

出力

データセットごとに、指定された文字を頭文字にもつ単語または”NA” を出力します。

入力例

1
ben likes bananas the best among many fruits because bananas are sweet and cheap
b
1
winners get to visit aizu and the university of aizu and make many friends as well
a
3
ask alex about
the answer for the
assignment on android apps
a
2
programming is both
a sport and an intellectual puzzle
c
0

出力例

bananas because ben best
aizu and as
about alex android answer apps
NA

Solution in Haskell (judge verdict: Accepted)

import Control.Monad

main :: IO ()
main = do
  n <- readLn
  if n == 0
    then return ()
    else do
      ls <- replicateM n getLine
      k <- getLine
      let ls' = filter (\x -> [head x] == k) (concatMap words ls)
      putStrLn $ solve ls'
      main

solve :: [String] -> String
solve ls = format (take 5 (foldl getName [] (sort (countName ls))))
  where
    getName :: [String] -> (String,Int) -> [String]
    getName acc (name,i) = name:acc

    countName :: [String] -> [(String,Int)]
    countName [] = []
    countName (x:xs) = (x,(count x (x:xs))):(countName (filter (\y -> x /= y) xs))
      where
        count :: String -> [String] -> Int
        count _ [] = 0
        count a (b:bs)
          | a == b = 1 + (count a bs)
          | otherwise = count a bs

    sort :: [(String,Int)] -> [(String,Int)]
    sort [] = []
    sort ((a,b):r) = (sort lower) ++ [(a,b)] ++ (sort higher)
      where
        lower = filter (\(c,d) -> (d < b) || ((d == b) && (c > a))) r
        higher = filter (\(c,d) -> (d > b) || ((b == d) && (c <= a))) r
        
    format :: [String] -> String
    format [] = "NA"
    format [x] = x
    format (x:xs) = x ++ " " ++ (format xs)