Problem:
問題 3

　ある工場では，各営業所から製品生産の注文を受けている．
前日の注文をまとめて，各製品の生産合計を求めたい．

　入力ファイルの１行目には注文データの数 n が書いてあり，
続く n 行には製品名と注文数が空白で区切られて書いてある．
製品名は5文字以内の英大文字で書かれている．
注文データには同じ製品が含まれていることもあり，順序はバラバラである．

　この注文データの中に現れる同じ製品の注文数を合計し，
出力ファイルに製品名と合計を空白を区切り文字として出力しなさい．
ただし，製品名に次の順序を付けて，その順で出力すること．

　順序：文字の長さの小さい順に，同じ長さのときは，前から比べて
最初に異なる文字のアルファベット順とする．

入力データにおける製品数，注文数とその合計のどれも106以下である．

　出力ファイルにおいては，
出力の最後の行にも改行コードを入れること．

入出力例

入力例1

5
A 20
B 20
A 20
AB 10
Z 10

出力例1

A 40
B 20
Z 10
AB 10

入力例2

5
AAA 20
ABA 20
AAA 20
AAB 20
AAA 20

出力例2

AAA 60
AAB 20
ABA 20

問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

Solution in Haskell (judge verdict: Accepted)

import Data.List (sortBy, groupBy)
import Control.Monad (forM_)

readTestcase :: IO [(String, Int)]
readTestcase = do
    nStr <- getLine
    readData (read nStr :: Int) []

readData :: Int -> [(String, Int)] -> IO [(String, Int)]
readData 0 res = do return res
readData n res = do
    line <- getLine
    let [id, numStr] = words line
    let num = read numStr :: Int
    readData (n - 1) ((id, num) : res)

-- False < True
compare' :: (String, Int) -> (String, Int) -> Ordering
compare' (a, _) (b, _)
    | (length a) /= (length b) = compare (length a) (length b)
    | otherwise = compare a b

sort' :: [(String, Int)] -> [(String, Int)]
sort' = sortBy compare'

equalFirst :: (String, Int) -> (String, Int) -> Bool
equalFirst x y = (fst x) == (fst y)

groupBy' :: [(String, Int)] -> [[(String, Int)]]
groupBy' = groupBy equalFirst

sum' :: [(String, Int)] -> (String, Int)
sum' xs = (id, acc)
    where
        id = fst $ head xs
        acc = sum $ map snd xs

main = do
    dat <- readTestcase
    let res = (map sum' (groupBy' (sort' dat)))
    forM_ res (\ (id, num) -> putStrLn (id ++ " " ++ (show num)))