1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | -- -- Problem: Find the 51000000000-th character of the string (wordNumber Infinity) -- where a wordNumber is defined as -- -- wordNumber 1 = "one" -- wordNumber 2 = "onetwo" -- wordNumber 3 = "onetwothree" -- wordNumber 15 = "onetwothreefourfivesixseveneightnineteneleventwelvethirteenfourteenfifteen" -- ... -- -- The answer should be presented as ( sum of all numbers up to that point -- , the 51000000000-th character -- ) {-# LANGUAGE BangPatterns #-} import Debug.Trace import Data.Int import Control.Monad ones = ["", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"] tens = ["", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"] teens = ["ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"] -- onesLengths = map (fromIntegral . length) ones -- tensLengths = map (fromIntegral . length) tens -- teensLengths = map (fromIntegral . length) teens -- As suggested on #haskell, pattern matching -- 'lensOnes n' should be faster than 'onesLengths !! n' lenOnes, lenTens, lenTeens :: Int64 -> Int64 lenOnes 0 = 0 lenOnes 1 = 3 lenOnes 2 = 3 lenOnes 3 = 5 lenOnes 4 = 4 lenOnes 5 = 5 lenOnes 6 = 3 lenOnes 7 = 5 lenOnes 8 = 5 lenOnes 9 = 4 lenTens 0 = 0 lenTens 1 = 3 lenTens 2 = 6 lenTens 3 = 6 lenTens 4 = 5 lenTens 5 = 5 lenTens 6 = 5 lenTens 7 = 7 lenTens 8 = 6 lenTens 9 = 6 lenTeens 0 = 3 lenTeens 1 = 6 lenTeens 2 = 6 lenTeens 3 = 8 lenTeens 4 = 8 lenTeens 5 = 7 lenTeens 6 = 7 lenTeens 7 = 9 lenTeens 8 = 8 lenTeens 9 = 8 -- wordify 123 = "onehundredtwentythree" -- This is only used once in presenting the final result character wordify :: Int64 -> String wordify n | n < 10 = ones !! fromIntegral n | n < 20 = teens !! (fromIntegral n-10) | n < 100 = splitterTen | n < 1000 = splitter 100 "hundred" | n < 1000000 = splitter 1000 "thousand" | n < 1000000000 = splitter 1000000 "million" where splitterTen = let (t, x) = n `divMod` 10 in (tens !! fromIntegral t) ++ wordify x splitter div suffix = let (t, x) = n `divMod` div in (wordify t) ++ suffix ++ wordify x -- Optimized version of length (wordify n) -- Used in number crunching wordLength n = wordLength' 0 n -- Tail recursive version wordLength' :: Int64 -> Int64 -> Int64 wordLength' !pad !n | n < 10 = lenOnes n + pad | n < 20 = lenTeens (n-10) + pad | n < 100 = splitterTen | n < 1000 = splitter 100 7 | n < 1000000 = splitter 1000 8 | otherwise = splitter 1000000 7 where splitterTen = let !(!t, !x) = n `divMod` 10 in wordLength' (lenTens t + pad) x splitter !d !suffix = let !(!t, !x) = n `divMod` d in wordLength' (wordLength' (suffix+pad) t) x -- Tail recursive -- n-th number (51000000000 in our problem) -> accumulated result -> list of 'zipped' left to try -- accumulated has the format (sum of numbers, current lengths of the whole chain, the current number) solve :: Int64 -> (Int64, Int64, Int64) -> [(Int64, Int64)] -> (Int64, Int64, Int64) solve !n !acc@(!sumNum, !sumLen, !curr) ((!num, !len):xs) | sumLen' >= n = (sumNum', sumLen, num) | otherwise = solve n (sumNum', sumLen', num) xs where sumNum' = sumNum + num sumLen' = sumLen + len solution :: Int64 -> (Int64, Char) solution !x = let (sumNum, sumLen, n) = solve x (0,0,1) (map (\n -> (n, wordLength n)) [1..]) in (sumNum, (wordify n) !! (fromIntegral $ x - sumLen - 1)) main = do print $ solution 1234 -- Make sure we are sane print $ solution 51000000000 |
LS0KLS0gUHJvYmxlbTogRmluZCB0aGUgNTEwMDAwMDAwMDAtdGggY2hhcmFjdGVyIG9mIHRoZSBzdHJpbmcgKHdvcmROdW1iZXIgSW5maW5pdHkpCi0tIHdoZXJlIGEgd29yZE51bWJlciBpcyBkZWZpbmVkIGFzCi0tCi0tIHdvcmROdW1iZXIgMSA9ICJvbmUiCi0tIHdvcmROdW1iZXIgMiA9ICJvbmV0d28iCi0tIHdvcmROdW1iZXIgMyA9ICJvbmV0d290aHJlZSIKLS0gd29yZE51bWJlciAxNSA9ICJvbmV0d290aHJlZWZvdXJmaXZlc2l4c2V2ZW5laWdodG5pbmV0ZW5lbGV2ZW50d2VsdmV0aGlydGVlbmZvdXJ0ZWVuZmlmdGVlbiIKLS0gLi4uCi0tCi0tIFRoZSBhbnN3ZXIgc2hvdWxkIGJlIHByZXNlbnRlZCBhcyAoIHN1bSBvZiBhbGwgbnVtYmVycyB1cCB0byB0aGF0IHBvaW50Ci0tICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsIHRoZSA1MTAwMDAwMDAwMC10aCBjaGFyYWN0ZXIKLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKCnstIyBMQU5HVUFHRSBCYW5nUGF0dGVybnMgIy19CgppbXBvcnQgRGVidWcuVHJhY2UKaW1wb3J0IERhdGEuSW50CmltcG9ydCBDb250cm9sLk1vbmFkCgpvbmVzID0gWyIiLCAib25lIiwgInR3byIsICJ0aHJlZSIsICJmb3VyIiwgImZpdmUiLCAic2l4IiwgInNldmVuIiwgImVpZ2h0IiwgIm5pbmUiXQp0ZW5zID0gWyIiLCAidGVuIiwgInR3ZW50eSIsICJ0aGlydHkiLCAiZm9ydHkiLCAiZmlmdHkiLCAic2l4dHkiLCAic2V2ZW50eSIsICJlaWdodHkiLCAibmluZXR5Il0KdGVlbnMgPSBbInRlbiIsICJlbGV2ZW4iLCAidHdlbHZlIiwgInRoaXJ0ZWVuIiwgImZvdXJ0ZWVuIiwgImZpZnRlZW4iLCAic2l4dGVlbiIsICJzZXZlbnRlZW4iLCAiZWlnaHRlZW4iLCAibmluZXRlZW4iXQoKLS0gb25lc0xlbmd0aHMgPSBtYXAgKGZyb21JbnRlZ3JhbCAuIGxlbmd0aCkgb25lcwotLSB0ZW5zTGVuZ3RocyA9IG1hcCAoZnJvbUludGVncmFsIC4gbGVuZ3RoKSB0ZW5zCi0tIHRlZW5zTGVuZ3RocyA9IG1hcCAoZnJvbUludGVncmFsIC4gbGVuZ3RoKSB0ZWVucwoKLS0gQXMgc3VnZ2VzdGVkIG9uICNoYXNrZWxsLCBwYXR0ZXJuIG1hdGNoaW5nCi0tICdsZW5zT25lcyBuJyBzaG91bGQgYmUgZmFzdGVyIHRoYW4gJ29uZXNMZW5ndGhzICEhIG4nCgpsZW5PbmVzLCBsZW5UZW5zLCBsZW5UZWVucyA6OiBJbnQ2NCAtPiBJbnQ2NApsZW5PbmVzIDAgPSAwCmxlbk9uZXMgMSA9IDMKbGVuT25lcyAyID0gMwpsZW5PbmVzIDMgPSA1Cmxlbk9uZXMgNCA9IDQKbGVuT25lcyA1ID0gNQpsZW5PbmVzIDYgPSAzCmxlbk9uZXMgNyA9IDUKbGVuT25lcyA4ID0gNQpsZW5PbmVzIDkgPSA0CgpsZW5UZW5zIDAgPSAwCmxlblRlbnMgMSA9IDMKbGVuVGVucyAyID0gNgpsZW5UZW5zIDMgPSA2CmxlblRlbnMgNCA9IDUKbGVuVGVucyA1ID0gNQpsZW5UZW5zIDYgPSA1CmxlblRlbnMgNyA9IDcKbGVuVGVucyA4ID0gNgpsZW5UZW5zIDkgPSA2CgpsZW5UZWVucyAwID0gMwpsZW5UZWVucyAxID0gNgpsZW5UZWVucyAyID0gNgpsZW5UZWVucyAzID0gOApsZW5UZWVucyA0ID0gOApsZW5UZWVucyA1ID0gNwpsZW5UZWVucyA2ID0gNwpsZW5UZWVucyA3ID0gOQpsZW5UZWVucyA4ID0gOApsZW5UZWVucyA5ID0gOAoKLS0gd29yZGlmeSAxMjMgPSAib25laHVuZHJlZHR3ZW50eXRocmVlIgotLSBUaGlzIGlzIG9ubHkgdXNlZCBvbmNlIGluIHByZXNlbnRpbmcgdGhlIGZpbmFsIHJlc3VsdCBjaGFyYWN0ZXIKd29yZGlmeSA6OiBJbnQ2NCAtPiBTdHJpbmcKd29yZGlmeSBuCiAgICB8IG4gPCAxMCAgICAgICAgID0gb25lcyAhISBmcm9tSW50ZWdyYWwgbgogICAgfCBuIDwgMjAgICAgICAgICA9IHRlZW5zICEhIChmcm9tSW50ZWdyYWwgbi0xMCkKICAgIHwgbiA8IDEwMCAgICAgICAgPSBzcGxpdHRlclRlbgogICAgfCBuIDwgMTAwMCAgICAgICA9IHNwbGl0dGVyIDEwMCAiaHVuZHJlZCIKICAgIHwgbiA8IDEwMDAwMDAgICAgPSBzcGxpdHRlciAxMDAwICJ0aG91c2FuZCIKICAgIHwgbiA8IDEwMDAwMDAwMDAgPSBzcGxpdHRlciAxMDAwMDAwICJtaWxsaW9uIgogICAgd2hlcmUKICAgICAgICBzcGxpdHRlclRlbiA9IGxldCAodCwgeCkgPSBuIGBkaXZNb2RgIDEwCiAgICAgICAgICAgICAgICAgICAgICBpbiAodGVucyAhISBmcm9tSW50ZWdyYWwgdCkgKysgd29yZGlmeSB4CiAgICAgICAgc3BsaXR0ZXIgZGl2IHN1ZmZpeCA9IGxldCAodCwgeCkgPSBuIGBkaXZNb2RgIGRpdgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbiAod29yZGlmeSB0KSArKyBzdWZmaXggKysgd29yZGlmeSB4CgotLSBPcHRpbWl6ZWQgdmVyc2lvbiBvZiBsZW5ndGggKHdvcmRpZnkgbikKLS0gVXNlZCBpbiBudW1iZXIgY3J1bmNoaW5nCndvcmRMZW5ndGggbiA9IHdvcmRMZW5ndGgnIDAgbgoKLS0gVGFpbCByZWN1cnNpdmUgdmVyc2lvbgp3b3JkTGVuZ3RoJyA6OiBJbnQ2NCAtPiBJbnQ2NCAtPiBJbnQ2NAp3b3JkTGVuZ3RoJyAhcGFkICFuCiAgICB8IG4gPCAxMCAgICAgICAgID0gbGVuT25lcyBuICsgcGFkCiAgICB8IG4gPCAyMCAgICAgICAgID0gbGVuVGVlbnMgKG4tMTApICsgcGFkCiAgICB8IG4gPCAxMDAgICAgICAgID0gc3BsaXR0ZXJUZW4KICAgIHwgbiA8IDEwMDAgICAgICAgPSBzcGxpdHRlciAxMDAgNwogICAgfCBuIDwgMTAwMDAwMCAgICA9IHNwbGl0dGVyIDEwMDAgOAogICAgfCBvdGhlcndpc2UgICAgICA9IHNwbGl0dGVyIDEwMDAwMDAgNwogICAgd2hlcmUKICAgICAgICBzcGxpdHRlclRlbiA9IGxldCAhKCF0LCAheCkgPSAgbiBgZGl2TW9kYCAxMAogICAgICAgICAgICAgICAgICAgICAgaW4gd29yZExlbmd0aCcgKGxlblRlbnMgdCArIHBhZCkgeAogICAgICAgIHNwbGl0dGVyICFkICFzdWZmaXggPSBsZXQgISghdCwgIXgpID0gbiBgZGl2TW9kYCBkCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluIHdvcmRMZW5ndGgnICh3b3JkTGVuZ3RoJyAoc3VmZml4K3BhZCkgdCkgeAoKLS0gVGFpbCByZWN1cnNpdmUKLS0gbi10aCBudW1iZXIgKDUxMDAwMDAwMDAwIGluIG91ciBwcm9ibGVtKSAtPiBhY2N1bXVsYXRlZCByZXN1bHQgLT4gbGlzdCBvZiAnemlwcGVkJyBsZWZ0IHRvIHRyeQotLSBhY2N1bXVsYXRlZCBoYXMgdGhlIGZvcm1hdCAoc3VtIG9mIG51bWJlcnMsIGN1cnJlbnQgbGVuZ3RocyBvZiB0aGUgd2hvbGUgY2hhaW4sIHRoZSBjdXJyZW50IG51bWJlcikKc29sdmUgOjogSW50NjQgLT4gKEludDY0LCBJbnQ2NCwgSW50NjQpIC0+IFsoSW50NjQsIEludDY0KV0gLT4gKEludDY0LCBJbnQ2NCwgSW50NjQpCnNvbHZlICFuICFhY2NAKCFzdW1OdW0sICFzdW1MZW4sICFjdXJyKSAoKCFudW0sICFsZW4pOnhzKQogICAgfCBzdW1MZW4nID49IG4gPSAoc3VtTnVtJywgc3VtTGVuLCBudW0pCiAgICB8IG90aGVyd2lzZSA9IHNvbHZlIG4gKHN1bU51bScsIHN1bUxlbicsIG51bSkgeHMKICAgIHdoZXJlCiAgICAgICAgc3VtTnVtJyA9IHN1bU51bSArIG51bQogICAgICAgIHN1bUxlbicgPSBzdW1MZW4gKyBsZW4KCnNvbHV0aW9uIDo6IEludDY0IC0+IChJbnQ2NCwgQ2hhcikKc29sdXRpb24gIXggPQogICAgbGV0IChzdW1OdW0sIHN1bUxlbiwgbikgPSBzb2x2ZSB4ICgwLDAsMSkgKG1hcCAoXG4gLT4gKG4sIHdvcmRMZW5ndGggbikpIFsxLi5dKQogICAgaW4gKHN1bU51bSwgKHdvcmRpZnkgbikgISEgKGZyb21JbnRlZ3JhbCAkIHggLSBzdW1MZW4gLSAxKSkKCm1haW4gPSBkbwogICAgcHJpbnQgJCBzb2x1dGlvbiAxMjM0IC0tIE1ha2Ugc3VyZSB3ZSBhcmUgc2FuZQogICAgcHJpbnQgJCBzb2x1dGlvbiA1MTAwMDAwMDAwMAo=


