競プロ鉄則 Haskell AtCoder 振り返り2
A2
問題:
制約:
-
は1以上100以下の整数N -
は1以上100以下の整数X -
は1以上100以下の整数A_1,A_2,⋯,A_N
入力:
提出したコード
main :: IO ()
main = do
a <- getLine
b <- getLine
let ls = map read $ words (a <> " " <> b) :: [Int]
let b = isContain (ls!!1) ((tail.tail) ls)
let res = if b then "Yes" else "No"
putStr res
isContain :: Int -> [Int] -> Bool
isContain _ [] = False
isContain a (x:xs) =
if a==x then True else isContain a xs
結果
AC 時間:2ms
警告
app/Main.hs:6:7: warning: [-Wname-shadowing]
This binding for ‘b’ shadows the existing binding
bound at app/Main.hs:4:3
|
6 | let b = isContain (ls!!1) ((tail.tail) ls)
| ^
ふつーに間違へて 同じ b を別のものに使ってしまった〜
でも エラーにはならなかった
考察
一行目の入力と二行目の入力をスペースでつないでから words函數を適用して 文字列のリストをつくり それら各々を Int型として read してゐます
そもそも
let x = (read . last . words) a
let as = (map read . words) b
と個別に定義してもよかったかもしれません
あと isContain の内容は any函數と同じだと思ひます
再提出
main :: IO ()
main = do
x <- getLine >>= return . read . last . words
as <- getLine >>= return . map read . words
let bin = any (==x) (as :: [Int])
putStr (if bin then "Yes" else "No")
時間: 1ms
となり コードは簡潔で 速くなった
付記
リストに適用する函數で last と tail と !! が出てきてゐます
例へば
last [1,2,3,4]
は 4
tail [1,2,3,4]
は [2,3,4]
(tail . tail) [1,2,3,4]
は [3,4]
[1,2,3,4]!!1
は 2
[1,2,3,4]!!0
は 1
[1,2,3,4]!!3
は 4
[1,2,3,4]!!4
は エラー
isContain :: Int -> [Int] -> Bool
isContain _ [] = False
isContain a (x:xs) =
if a==x then True else isContain a xs
について
一行目: isContainといふ函數は Int型 と [Int]型をとって Bool型を返すよ っと宣言してゐます
この行がなくても コンパイラが型を判断してくれて動くと思ふのですが かういふ「型注釈」があると 函數の 「何と何から何をつくる」みたいな 全體像が把握しやすいので 書くのがオススメです
二行目: isContainに渡される ひとつめの値が何であらうが ふたつ目のリストが空リスト(要素が何もない)であれば False(偽)といふ Bool型の値を返します
三行目: リストが空でなければ ひとつめの値を a とし ふたつめのリストを 頭とおしりに分けて x, xs にそれぞれ指定します
例へば リストが [1,2,3,4]
であれば x = 1, xs = [2,3,4]
となります
四行目: もし a と x が等しければ True(真) といふ Bool型の値を返し さもなくば isContain函數に a と 殘りのリスト xs を渡します
んで any といふ函數は 以上のことを 簡潔に より効率的にやるものです(と理解してゐます)
毒(独)談
「なんとか初心者」っていふ表現って あまり意味をなさない表現だと思ふ
それを言ったところで 相手には「この人がどこまで なんとか を知ってゐるのか」といふことについて 全く分からない
「初心者」といふ言葉が 各々の主観でしか使はれ得ないから 言ふならば この言葉は
「ぼくちん このテーマに あんま自信ないから 間違ったこと言っても ゆるしてちょ」
といふことを傳へたいために使はれてゐる氣がする
子供のころは 自分の考へたことを そのまんま傳へやうとするのに
いつの間にか 人と比べる習慣がついてしまふ
いつしか 思ったことを言ってくれる人が まはりにも少くなって
さらに 「かう思はれるんぢゃ・・・」みたいな妄想が強くなっていく
なんか そんなの ヴァカらしいから 自分の主観を堂々と表現したいな〜 と思ふ今日このごろ
B2
問題:
制約:
1≤A≤B≤100 - 入力はすべて整数
入力:
提出コード
main :: IO ()
main = do
a <- getLine
let ls = map read $ words a :: [Int]
let b = isContain (head ls) (last ls)
let res = if b then "Yes" else "No"
putStr res
isContain :: Int -> Int -> Bool
isContain i n
| i > n = False
| otherwise =
if mod 100 i == 0 then True else
isContain (i+1) n
結果
AC 時間:2ms 警告なし
考察
連續した整数のリストをつくって A2問題みたいに any函數を適用したら 速くなるだらうか
再提出
main :: IO ()
main = do
[a,b] <- getLine >>= return . map read . words
let bin = any (\i -> mod 100 i == 0) [a..b]
let res = if bin then "Yes" else "No"
putStr res
結果
AC 時間:1ms
警告
app/Main.hs:3:37: warning: [-Wtype-defaults]
• Defaulting the type variable ‘b0’ to type ‘Integer’ in the following constraints
(Read b0) arising from a use of ‘read’ at app/Main.hs:3:37-40
(Eq b0) arising from a use of ‘==’ at app/Main.hs:4:34-35
(Integral b0) arising from a use of ‘mod’ at app/Main.hs:4:24-26
(Num b0) arising from the literal ‘100’ at app/Main.hs:4:28-30
(Enum b0)
arising from the arithmetic sequence ‘a .. b’
at app/Main.hs:4:40-45
• In the first argument of ‘map’, namely ‘read’
In the first argument of ‘(.)’, namely ‘map read’
In the second argument of ‘(.)’, namely ‘map read . words’
|
3 | [a,b] <- getLine >>= return . map read . words
|
速くなった!!
mod a b
は a を b で割った余りを出すんだけれど a や b は Integral といふ型クラスに含まれる型である と定義されてゐるから 必ずしも Int型ぢゃない っていふか ここでは Integer型と解釈されてるみたい
なんで ちゃんと 型制約を書かう
main :: IO ()
main = do
[a,b] <- getLine >>= return . map read . words
let bin = any (\i -> mod 100 i == 0) [(a::Int)..b]
let res = if bin then "Yes" else "No"
putStr res
これで警告はなくなりました!
ちなみに mod 100 i
の 100
に 型制約をつけて (100::Int)
としたコードを提出したら テストケースのひとつが 2ms かかってゐました
付記
えっと まづ [a..b]
から
例へば [3..9]
といふのは [3,4,5,6,7,8,9]
といふことです
こんなんでいいかな?
なんか 「aからbまでを連續して並べたリストをつくります」とか言ふより 例を示した方が分かりやすいんぢゃないかって氣がする〜
(\i -> mod 100 i == 0)
といふのは それ全體がひとつの函數です〜
この函數は ひとつの値をとって それを i とし mod 100 i
の値(100をiで割った余り) と 0 を比べて 等しかったら True 等しくなければ False を返します
isContain :: Int -> Int -> Bool
isContain i n
| i > n = False
| otherwise =
if mod 100 i == 0 then True else isContain (i+1) n
について
このisContain函數は Int型の値 と Int型の値 をとって Bool型の値を返します
二行目:とる値を それぞれ i n とします
三行目:もし i > n なら(iがnより大きいなら) False を返します
四行目:さうでなければ
五行目:mod 100 i
が 0 であれば True を さうでなければ isContain 函數に i+1 と n を入れた結果を返します
ここで一句
くりかへす 日々もわずかに ことなれば
かならず來せし 春のいとしさ
Discussion