👌
Nimの競技プログラミング標準入出力 まとめ
はじめに
最近 nim
という言語を競技プログラミングで使い始めました。
触り始めたばかりであり、いつも標準入出力でググっているのでまとめることにします。
ゆくゆくは nim
のマクロの機能なども理解して、他の方がやっている便利な入力方法も理解したいです。
import
import sequtils
import strutils
import strformat
以上の import をコードの先頭に置いていることを前提としています。
標準入力
1行に1つのみ
import sequtils
import strutils
import strformat
# 3
let a = stdin.readLine.parseInt
# hello, world
let b = stdin.readLine
# float
let c = stdin.readLine.parseFloat
echo &"{a} {b} {c}"
1行に複数の変数
import sequtils
import strutils
import strformat
# 4 10 32
var a, b, c: int
(a, b, c) = stdin.readLine.split.map parseInt
echo &"{a} {b} {c}"
# 4 hello 32.3
# もっといい方法あったら教えて下さい... (これ微妙です)
let s = stdin.readLine.split
var
x = parseInt(s[0])
y = s[1]
z = parseFloat(s[2])
echo &"{x} {y} {z}"
@jiro4989 さんに、複数の型の変数の受け取り方をコメント欄で教えていただきました。
strscans
モジュールを用いると複数の型の変数に代入できます。
C / C++ の scanf のように書けて便利です。
import strscans, strformat
# 4 hello 32.3
var
x: int
y: string
z: float
discard stdin.readLine.scanf("$i $w $f", x, y, z)
echo &"{x} {y} {z}"
1行に配列
import sequtils
import strutils
import strformat
#[
3
10 20 30
]#
let N = stdin.readLine.parseInt
let a = stdin.readLine.split.map parseInt
#[
3
a is 10 20 30
]#
echo N
echo "a is ", a.join " "
N行に1つの変数
template newSeqWith(len: int; init: untyped): untyped
template
は AST で動く置換アルゴリズムで、コンパイル時に置換されるものらしいです。(!=
なども実行時に置換される。)
import sequtils
import strutils
import strformat
#[
3
abc
def
geh
]#
var N = stdin.readLine.parseInt
let S = newSeqWith(N, stdin.readLine)
#[
3
@["abc", "def", "geh"]
]#
echo N
echo S
discard """
2
10
20
"""
N = stdin.readLine.parseInt
let A = newSeqWith(N, stdin.readLine.parseInt)
# @[10, 20]
echo A
N行に複数の変数
template mapIt(s: typed; op: untyped): untyped
mapIt
は、型がコンパイル時に明示的である s の要素それぞれに対して op の操作をしたものを返します。
let a = (0..<10).toSeq.mapIt(it*2)
は、@[0, ..., 9]
の要素それぞれに対して2倍の操作をする proc が適用されています。
ここで、it
は各要素が代入されて与えられます。
import sequtils, strutils, algorithm
discard """
https://atcoder.jp/contests/abc194/tasks/abc194_b
3
1 10
2 30
4 30
"""
var N = stdin.readLine.parseInt
let ab = (0..<N).mapIt(stdin.readLine.split.map parseInt)
# @[@[1, 10], @[2, 30], @[4, 30]]
# 多次元配列として入力する
echo ab
discard """
2
1 20
4 14
"""
N = stdin.readLine.parseInt
var a, b = newSeq[int](N)
for i in 0..<N:
(a[i], b[i]) = stdin.readLine.split.map parseInt
# @[1, 4]@[20, 14]
echo a, b
H行W列の数列
import sequtils, strutils, algorithm
#[
https://atcoder.jp/contests/abc183/tasks/abc183_c
3 2
]#
var H, W: int
(H, W) = stdin.readLine.split.map parseInt
# @[@[0, 0], @[0, 0], @[0, 0]]
# 初期化のみ
var A = newSeqWith(H, newSeq[int](W))
echo A
#[
1 2
3 4
5 6
]#
var B = mapIt(0..<H, stdin.readLine.split.map parseInt)
# @[@[1, 2], @[3, 4], @[5, 6]]
echo B
#[
1 2
3 4
5 6
]#
var C = newSeq[seq[int]](H)
for i in 0..<H:
C[i].add(stdin.readLine.split.map parseInt)
# @[@[1, 2], @[3, 4], @[5, 6]]
echo C
標準出力
配列スペース区切り
import sequtils, strutils, algorithm
# 1 2 3
let a = @[1, 2, 3]
echo a.join " "
配列改行区切り
import sequtils, strutils, algorithm
#[
1
2
3
]#
let a = @[1, 2, 3]
echo a.join "\n"
浮動小数点の出力
strformat を使うと Python の f
文字列のように出力できます。
競技プログラミングでは、浮動小数点の桁数を要求することが多いです。
そのため、fmt
を用いて {変数:.10f}
のようにすることで桁数を固定できます。
import strformat
let a = 2525.0 / 2020
echo fmt"{a:.20f}"
Discussion
strscansモジュールで、文字列からの読み取りと変数への代入を同時にやってくれるマクロがあります。
あんまり文字数的には減らないですけれど、少しスッキリ書けるようになります。
うぉぉ,ありがとうございます!><
この書き方とても好きです
Cにトランスコンパイルする,嬉しさを感じますね...
こちらの書き方も追加させていただこうと思います><