🥕

2024/08/18に公開

## A5

3枚のカードの合計をKにするような書き方は何通りありますか。

• Nは1以上3000以下の整数
• Kは3以上9000以下の整数

N K

#### 提出コード

calc :: (Int,Int,Int) -> Int
calc (a,b,c)
| a==b && b==c = 1
| a==b || b==c || a==c = 3
| otherwise = 6

main :: IO ()
main = do
ints <- getLine >>= return.map read.words
let k = last ints
let nl = [1::Int,2..n]
print $sum$ map calc [(a,b,c)|a<-nl,b<-[a..n],c<-[b..n],a+b+c==k]


#### 結果

AC 時間：1411ms 警告なし

#### 試行

  ints <- getLine >>= return.map read.words
let k = last ints


の部分は

  [n,k] <- getLine >>= return . map read . words


とかけます

main :: IO ()
main = interact $\inp -> (map read . words) inp & \ls -> case ls of [n,k] -> show$ sum $map calc [(a,b,c)|a<-[1::Int,2..n],b<-[a..n],c<-[b..n],a+b+c==k] _ -> ""  のやうにすると 實行時間が2秒を越えてしまひ 失敗します いろいろと試したので main函數のコードと 實行結果を載せてをきます #### 1 main = interact$ \inp -> (map read . words) inp & \[n,k] ->
show $sum$
map calc [(a,b,c)|a<-[(1::Int)..n],b<-[a..n],c<-[b..n],a+b+c==k]


app/Main.hs:10:52: warning: [-Wincomplete-uni-patterns]
Pattern match(es) are non-exhaustive
In a lambda abstraction:
Patterns of type ‘[Int]’ not matched:
[]
[_]
(_:_:_:_)
|
10 | main = interact $\inp -> (map read . words) inp & \[n,k] -> | ^^^^^^^^^^...  #### 2 main = interact$ \inp -> (map read . words) inp & \ls ->
case ls of
[n,k] -> show $sum$ map calc [(a,b,c)|a<-[1::Int,2..n],b<-[a..n],c<-[b..n],a+b+c==k]
_ -> ""


main = interact $\inp -> (map read . words) inp & \ls -> case ls of [n,k] -> let nl = [(1::Int)..n] in show$ sum $map calc [(a,b,c)|a<-nl,b<-[a..n],c<-[b..n],a+b+c==k] _ -> ""  時間： 2207ms 警告なし #### 4 main = interact$ \inp -> (map read . words) inp & \ls ->
case ls of
[n,k] -> let nl = [1::Int,2..n]
in show $sum$ map calc [(a,b,c)|a<-nl,b<-[a..n],c<-[b..n],a+b+c==k]
_ -> ""


#### 5

main = do
[n,k] <- getLine >>= return.map read.words
let nl = [1::Int,2..n]
print $sum$ map calc [(a,b,c)|a<-nl,b<-[a..n],c<-[b..n],a+b+c==k]


AC 時間：1421ms 警告なし

#### 6

main = do
[n,k] <- getLine >>= return.map read.words
let nl = [(1::Int)..n]
print $sum$ map calc [(a,b,c)|a<-nl,b<-[a..n],c<-[b..n],a+b+c==k]


#### 7

main = do
[n,k] <- getLine >>= return.map read.words
print $sum$ map calc [(a,b,c)|a<-[(1::Int)..n],b<-[a..n],c<-[b..n],a+b+c==k]


#### 8

main = do
[n,k] <- getLine >>= return.map read.words
print $sum$ map calc [(a,b,c)|a<-[1::Int,2..n],b<-[a..n],c<-[b..n],a+b+c==k]


AC 時間：1421ms 警告なし

#### 考察

ひとつは interactを使って書いたときと 書かなかったとき
この場合 interactを使って書くと もうひとつの条件がどんな場合でも 2秒を越えます
まうひとつは 連続した整数のリストをつくるときに
(A) [1::Int,2..n] と書いたときと
(B) [(1::Int)..n] と書いたとき
interactを使はなくても (B)のやうに書くと 2秒を越え失敗します
このリストを一度變數に束縛した場合(nl)と さうしなかった場合の2通りをそれぞれ試しましたが 結果は ほとんど變はりませんでした
これらの原因は 私には分かりません

ただ (B)の場合の遅れについて ちょっと予想できるのは 1..n と書いたとき 1の次が2である といふことをコンパイラーが判断するために何かしらの計算がなされてゐるだろう といふことで
それに對して (A) は 1,2..n と 1の次が2であることが明示されてゐるので 1の次が2であることを確定するための計算をする必要がない ・・・のかな なんて思ひました
あと interact についてですが これは 外部から文字列をとってきて 純粋な計算として利用できるやうにするための函數 という風に考へられます
だから とってきた純粋な文字列を出発點として いろいろな操作を加へていきます
ですが getLine からパターンマッチで 純粋な整数のリストを取り出すやうな
[n,k] <- getLine >>= return.map read.words
といった書き方だと 純粋なものとして扱ふ對象が はじめから 整数のリストだけです
つまり interactを使ふと 純粋な計算の對象が 文字列から始まるのに對し 初めからパターンマッチをした場合は 純粋な計算の對象が 整数のリストから始まることになり それだけ對象が制限されてゐるために 計算速度も速くなるのではないでせうか
こんなふうに考へると interactはなるほど便利な函數なのですが 入力された文字列情報を 色々な形に變換してから パターンマッチして計算する場合 ただ自分の欲しいパターンを書いただけだと 他のパターンはどうすんねん と警告されるし case文で場合分けするのは 何かちょっと 美しくない といふか 面倒臭いやうな感じになってしまふことが ちょっと分かった氣がしました