解法に関する解説は公式がやっているので、F#での実装や.NETに関連したことについて自分のわかる範囲で。
A - Keyboard
let s = stdin.ReadLine()
let t = stdin.ReadLine()
match s with
| "Y" -> t.ToUpper()
| _ -> t
|> stdout.WriteLine
.NETのライブラリにToUpper()
という小文字を大文字に変えてくれるメソッドがあるのでそれを使えばOK。
String.ToUpper メソッド (System) | Microsoft Docs
パターンマッチを使っていますが、別にif..then..else
でももちろんOK。
B - Futon
何故か問題の意味が理解できなくてかなり時間がかかってしまった。
let [|H;W|] = stdin.ReadLine().Split() |> Array.map int
let S = [|for i=0 to H-1 do stdin.ReadLine()|]
let mutable ans = 0
for i=0 to H-1 do
for j=0 to W-2 do
let s = S.[i].[j..j+1]
if not (s |> String.exists(fun x -> x='#')) then ans <- ans + 1
for i=0 to H-2 do
for j=0 to W-1 do
let s = S.[i].[j].ToString() + S.[i+1].[j].ToString()
if not (s |> String.exists(fun x -> x='#')) then ans <- ans + 1
ans |>
stdout.WriteLine
実際、もう少し綺麗に書けそうな気もしますが……。
あとFSharp.Collections.List
を使うとインデックスを用いたアクセスが遅くなるので配列の方が良い。
C - Neq Min
最初、「この書き方だとTLEになるよね」と思いつつTLEになるパターンで出しました😂
let N = stdin.ReadLine() |> int
let p = stdin.ReadLine().Split() |> Array.map int
let memo : int[] = Array.zeroCreate 200001
let mutable minNum = 0
for i=0 to N-1 do
let rec f n =
if memo.[n] = 0 then n
else f (n+1)
memo.[p.[i]] <- memo.[p.[i]]+1
minNum <- if p.[i] = minNum then (f minNum) else minNum
minNum |> printfn "%d"
例のごとく、List
ではなく配列でないとインデックスを用いた要素のアクセスが遅いので、どの整数が出現したかどうか記録するコレクションは配列を用います。
C#で競技プログラミングをし続ける人のためのTipsにもあるように、C#ではConsole.WriteLine
が低速であるのと同様に、F#のprintfn
も内部でConsole.Out
を使っているので遅いです。
このままだと800msぐらいかかるので、文字列の連結やSystem.Text.StringBuilder
クラスを使う、AutoFlush
のプロパティをOFFにした独自の出力方法を使うなど、何かしら工夫をして最後に一気に出力する方が本当は良いです。
いい加減AtCoder用のテンプレートプロジェクトを作っておく必要性を感じています。
open System.Collections.Generic
let N = stdin.ReadLine() |> int
let mutable ans = 0
let s = new HashSet<int>() //let mutable s = Set<int> [||]
let sb = System.Text.StringBuilder()
let rec g n =
if s.Contains(n) |> not then n
else g (n+1)
for p in stdin.ReadLine().Split() do
if s.Add(p |> int) then ans <- g ans // s <- p |> int |> s.Add
sb.AppendLine(ans.ToString()) |> ignore
sb.ToString() |> stdout.Write
終了後、他のC#の回答を見てHashSet
などを使ってみた場合はこちら。再帰関数をwhile..do
に変えることもできますが、再帰の方が誤差かもしれないが速い。あとfor
ループの外で関数定義した方が数十ms程度かもしれませんが速い。
ちなみに、コメントで示したようにF#のSet
をmutable
にして使ったり、再帰を利用して使ったりしても遅いのでおとなしくSystem.Collections.Generic.HashSet
を使った方がよさげです。
おわりに
最近本腰を入れて始めたばかりですが、F#での参加者は非常に少ないのでこれからも何かしらの何かを書いていきたいところです。