AtCoderに登録したら解くべき精選過去問10をIoで解いてみた

# はじめに
誰もやってなさそうな言語で競プロをやるシリーズ第5弾[^5th]、AtCoder Beginners Selection の問題[^abs]を、プロトタイプベースオブジェクト指向プログラミング言語「Io」で解いてみました。

競プロを知っている方向けのIoの布教記事となります。

[^abs]: [AtCoder に登録したら次にやること ～ これだけ解けば十分闘える！過去問精選 10 問 ～](https://qiita.com/drken/items/fd4e5e3630d0f5859067)(@drken さん) にて紹介されている過去問題

[^5th]: 過去の記事は 「[AtCoderに登録したら解くべき精選過去問10をTeXで解いてみた](https://qiita.com/Mopepe51/items/19ebc7c2171536580ee4)」、「[〃JSFuck](https://qiita.com/Mopepe51/items/0d5a5a79b8772c78177f)」、「[〃プロデル](https://qiita.com/Mopepe51/items/fe35a9e02f1b07666448)」、「[〃LabVIEW](https://qiita.com/Mopepe51/items/1709a9ae93366883bd0c)」となっています

現在のところ Io はAtCoderで使用可能な言語に含まれていないのでローカル環境でテストだけしています。
使用環境はUbuntu 18.04 LTS on WSL。環境構築については以前記事にしたので**[こちら](https://qiita.com/Mopepe51/items/3e12eeca9d9794dbef13)**をご覧ください[^1]。

[^1]: 環境構築記事の通り、プロジェクトをクローンしてきてmakeする方法だと一部パッケージが正常に読み込めないため「[#バイナリからのインストール](https://qiita.com/Mopepe51/items/3e12eeca9d9794dbef13#%E3%83%90%E3%82%A4%E3%83%8A%E3%83%AA%E3%81%8B%E3%82%89%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)」の項に従ってインストールしています。


# Ioの解説

Ioは純粋なプロトタイプベースオブジェクト指向言語です。Ioの基礎的な文法は非常に単純なので、同様にプロトタイプベースで動作するJavascriptやLuaなどの言語の理解に役立つのではないかと思います。

Ioはすべての動作が「オブジェクトへの**メッセージ**[^m]送信」だけで成りたっています。
オブジェクトはメッセージを受け取るとメッセージと名前の一致する「**スロット**」を検索します。該当するスロットが見つかればそのスロットに対応するメソッドを実行、戻り値があれば値を返します。
オブジェクトを実質的に {スロット名→その値} というハッシュテーブルだとみなすとわかりやすいでしょう。

各オブジェクトにはそのオブジェクトの「**プロトタイプ**」が設定されており、受け取ったメッセージに該当するスロットが存在しなければ自身のプロトタイプにメッセージをたらい回しします。

[^m]: 以下太字はテクニカルタームとしての語を意味します。

例として`"Hello, world!" print`という文を見てみましょう。
`"Hello, world!"`は文字列リテラルですが、これは`Sequence`というオブジェクトをプロトタイプに持ち、スロットは何もないオブジェクトです。

```io
Io> "Hello, world!" slotNames
==> list()
// slotNamesでスロットの一覧が取得される
```
これに`print`というメーッセージが送られていますが、`print`というスロットは無いのでプロトタイプの`Sequence`に`print`を送ります。
`Sequence`は

```io
Sequence slotNames
==> list(asJson, linePrint, duplicateIndexes, pathComponent, urlDecoded, removeSeq, bitwiseAnd, asCapitalized, log, uppercase, findSeq, replaceSeq, logicalOr, +, beginsWithSeq, containsAnyCaseSeq, square, sizeInBytes, cos, byteAt, asIoPath, removeEvenIndexes, <=, endsWithSeq, validEncodings, between, preallocateToSize, asBinarySignedInteger, sqrt, asDecodedList, size, repeated, isSymbol, interpolate, setSize, copy, removeSlice, beforeSeq, cloneAppendSeq, asLowercase, alignLeftInPlace, bitCount, afterSeq, findNthSeq, abs, lstrip, asBuffer, log10, max, slice, z, print, replaceFirstSeq, translate, cPrint, <, at, reverseFindSeq, appendSeq, encoding, acos, product, atPut, setItemsToDouble, asOSPath, Max, foreach, -, stringByExpandingTilde, setItemType, asSymbol, sinh, removeAt, set, sum, betweenSeq, /=, inclusiveSlice, clipAfterSeq, addEquals, atan, reverse, unpack, splitAt, setZ, asNumber, withStruct, removeOddIndexes, alignLeft, ceil, bitwiseNot, setItemsToLong, itemCopy, orderedSplit, tanh, asList, asFixedSizeType, removeSuffix, unescape, with, removeLast, >=, asBase64, validItemTypes, asMutable, normalize, exclusiveSlice, replaceMap, inSlice, asUCS4, x, floor, clipBeforeSeq, isUppercase, percentEncoded, lowercase, rootMeanSquare, asUppercase, alignCenter, sort, convertToFixedSizeType, asFile, append, isZero, empty, +=, toBase, rangeFill, cloneAppendPath, asin, sequenceSets, asStruct, zero, lastPathComponent, setEncoding, min, occurancesOfSeq, convertToItemType, split, itemSize, Min, capitalize, y, asSimpleString, strip, pack, findSeqs, percentDecoded, isEmpty, setY, *=, >, -=, asBinaryNumber, contains, /, splitNoEmpties, asBinaryUnsignedInteger, .., asUTF8, itemType, justSerialized, cosh, makeFirstCharacterLowercase, atInsertSeq, fromBase, clipBeforeEndOfSeq, sin, bitAt, meanSquare, negate, mean, prependSeq, containsSeq, slicesBetween, removePrefix, *, reverseInPlace, asString, isEqualAnyCase, whiteSpaceStrings, escape, bitwiseXor, alignRight, tan, urlEncoded, leaveThenRemove, interpolateInPlace, fileName, isLowercase, isMutable, fromBase64, distanceTo, insertSeqEvery, clipAfterStartOfSeq, hash, appendPathSeq, pathExtension, asHex, asMessage, makeFirstCharacterUppercase, exSlice, dotProduct, bitwiseOr, asUCS2, rstrip, setX)
```
のように文字列の様々な機能が実装されたスロットが存在します。ここに`print`スロットも存在し、自身を標準出力に出力するメソッドが対応していますので、`Hello, world!`が出力されます。

メソッドによって値が返されればそのオブジェクトに更にメッセージを送ることでメソッドチェーンが実現可能です。[例：9. ABC 049 C - Daydream](#9-abc^049-c---daydream)


文字列に`type`というメッセージを送ると`"Sequence"`と帰ってきます。つまり文字列のtypeは「Sequence」なのですが、これは`Sequence`クラスがあるわけではありません。Ioに「クラス」と「インスタンス」の区別はなく、全て等しく「プロトタイプ」です。

```io
Io>"Hello, world!" type
==> Sequence
```

では何故`"Hello, world!" type`は`"Sequence"`なのかというと`Sequence`がスロット`type`を持っていてその値が`"Sequence"`だからです。Ioでは大文字で始まるオブジェクトを作成すると自動でその変数名を持った`type`スロットが作成されます。これであるオブジェクトの**クローン**(そのオブジェクトをプロトタイプに持つ新たなオブジェクト)を小文字で作れば「子」は同じtypeを持つようになるので「種類」が規定され、大文字でクローンすればメソッドを継承した新しい「種類」ができるという意味をつけ、判別しやすくしていますが、結局操作の方法は同じです。

# ジャッジ方法

可能な限り公式のdropboxに公開されているものを使用しますが、見つけられなかったものは考えられるコーナーケースを含んだテストケースを作成し判定します[^test]。

[^test]: 使用したテストケースデータは https://github.com/Yukishita26/abs-solve/tree/master/testcases にまとめました。

```bash

$ EXE="hoge"
$ PTH="fuga"
$ (/usr/bin/time -f "${EXE} ${PTH}: %U s, %M kB" io ${EXE}.io < ../testcases/${EXE}/in/${PTH}.txt) 2>> ./resultout.txt | diff - ../testcases/${EXE}/out/${PTH}.txt
```
のようにdiffで正答と比較し、timeで実行時間と使用メモリをチェックしていきます。timeの出力は標準エラー出力に出るので、うまいことdiffの結果はコンソールに、timeの結果は`./res/"${EXE}-${PTH}_out.txt"`に

```
0 ex1: 0.01s, 5000 kB
```

のように出力されます。diffの出力なし、かつtimeの結果が制約以内ならばACとみなします。（一部答えが複数存在するものがあるのでこれは適宜対応）

# 解法
## 0. [practice contest A - Welcome to AtCoder](https://atcoder.jp/contests/abs/tasks/practice_1)

```io
readln := method(
    File standardInput readLine
)
a := readln asNumber
l := readln split
b := l at(0) asNumber
c := l at(1) asNumber
s := readln
writeln(a + b + c, " ", s)
```

まずは出入力の確認ということで0番。ちょっと長いので一行読み込みのメソッドを作成しました。

トップレベルに定義した変数は実はプロトタイプチェーンの一番根本のオブジェクトである「`Object`のプロトタイプ」のスロットとして定義されています。`:=`はスロット作成の演算子です。

```io
Io> Object proto
==>  Object_0x68c6d0:
  Lobby            = Object_0x68c6d0
  Protos           = Object_0x68c470
  _                = Object_0x68c6d0
  exit             = method(...)
  forward          = method(...)
  set_             = method(...)
```

だったのがプログラムの実行後は

```io
Io> Object proto
==>  Object_0x68c6d0:
  Lobby            = Object_0x68c6d0
  Protos           = Object_0x68c6d0
  _                = Object_0x68c6d0
  a                = 1
  b                = 2
  c                = 3
  exit             = method(...)
  forward          = method(...)
  l                = list(2, 3)
  readln           = method(...)
  s                = "test"
  set_             = method(...)
```

のようにプログラム中で定義した変数がスロットに加わっていることがわかります。[^3]

[^3]: つまりビルトインのオブジェクトに変更を加えられるということです。Rubyのオープンクラスのようなメタプログラミングが可能です。

引数0の関数呼び出しではメンバ変数のようにカッコが要らないのが特徴的ですね。
配列のインデックスアクセスには`at`(1引数メソッド)、文字列の結合は`..`(2項演算子[^niko])を使います。

[^niko]: 「2項演算子」は1引数メソッドのシュガーシンタックスです。

結果： AC / 0.04s, 5984 kB
<details><summary>個別ケース結果</summary><div>0 ex1: 0.04 s, 5988 kB
0 ex2: 0.04 s, 5984 kB
</div></details>

## 1. [ABC 086 A - Product](https://atcoder.jp/contests/abs/tasks/abc086_a)
```io
l := File standardInput readLine split
a := l at(0) asNumber
b := l at(1) asNumber
if(a * b % 2 == 0) then(
  "Even" println
) else(
  "Odd" println
)
```
もちろん標準入力読み込みのメソッドを作らず1行で書くこともできます。

条件分岐はこんな感じに書きます。
`if`も`Object`のスロットに定義されているメソッドです。徹底していますね。

標準出力は#0では`writeln(hoge)`と書きましたが、`<Object> println`のようにオブジェクトが持っている`println`メソッドを呼び出すことでも可能です。

結果： AC / 0.06 s, 5996 kB
<details><summary>個別ケース結果</summary><div>1 0_000: 0.06 s, 5996 kB
1 0_001: 0.04 s, 5996 kB
1 1_002: 0.04 s, 5996 kB
1 1_004: 0.04 s, 5992 kB
1 1_005: 0.04 s, 5992 kB
1 1_006: 0.04 s, 5996 kB
</div></details>

## 2. [ABC 081 A - Placing Marbles](https://atcoder.jp/contests/abs/tasks/abc081_a)

```io
s := File standardInput readLine
r := 0
for(i, 0, s size - 1,
  r = r + if(s at(i) == "1" at(0), 1, 0)
)
r println

```
繰り返しはこんな感じ。
`if`は3つ引数を与えると第1,2引数の値を返す、つまりif式として使うことができます。
ちなみに`for`も式で、繰り返し最後の文の値を返します。

結果： AC / 0.03 s, 5988 kB
<details><summary>個別ケース結果</summary><div>2 00_example_01: 0.01 s, 5988 kB
2 00_example_02: 0.03 s, 5984 kB
2 01: 0.03 s, 5988 kB
2 02: 0.01 s, 5988 kB
2 03: 0.01 s, 5988 kB
2 04: 0.01 s, 5988 kB
2 05: 0.03 s, 5988 kB
2 06: 0.00 s, 5992 kB
</div></details>

## 3. [ABC 081 B - Shift Only](https://atcoder.jp/contests/abs/tasks/abc081_b)

```io
readln := method(
  File standardInput readLine
)
n := readln asNumber
l := readln split
a := list()
m := 100
for(i, 0, n - 1,
  a := l at(i) asNumber; c := 0;
  while(a % 2 == 0,
    a = a / 2 floor; c = c + 1
  );
  m = m min(c)
)
m println
```
forの第4引数のところのように、式を複数続けて実行するときは`;`で繋ぎます。

結果： AC / 0.06 s, 6016 kB
<details><summary>個別ケース結果</summary><div>
3 sample1: 0.04 s, 6012 kB
3 sample2: 0.04 s, 6016 kB
3 sample3: 0.04 s, 6016 kB
3 1: 0.04 s, 6016 kB
3 2: 0.04 s, 6008 kB
3 3: 0.04 s, 6012 kB
3 4: 0.04 s, 6012 kB
3 5: 0.06 s, 6012 kB
3 6: 0.04 s, 6012 kB
3 7: 0.04 s, 6012 kB
</div></details>

## 4. [ABC 087 B - Coins](https://atcoder.jp/contests/abs/tasks/abc087_b)

```io
readln := method(
  File standardInput readLine
)
a := readln asNumber
b := readln asNumber
c := readln asNumber
x := readln asNumber / 50
result := 0
for(i, 0, a,
  for(j, 0, b,
    if(0 <= x - i * 10 - j * 2 and x - i * 10 - j * 2 <= c, result = result + 1)
  )
)
result println
```

結果： AC / 0.06 s, 5988 kB
<details><summary>個別ケース結果</summary><div>4 sample01: 0.04 s, 5988 kB
4 sample02: 0.04 s, 5992 kB
4 sample03: 0.04 s, 5988 kB
4 01: 0.04 s, 5988 kB
4 02: 0.04 s, 5988 kB
4 03: 0.04 s, 5988 kB
4 04: 0.06 s, 5988 kB
4 05: 0.04 s, 5988 kB
4 06: 0.04 s, 5984 kB
4 07: 0.06 s, 5984 kB
4 08: 0.03 s, 5988 kB
4 09: 0.04 s, 5988 kB
4 10: 0.04 s, 5988 kB
</div></details>

## 5. [ABC 083 B - Some Sums](https://atcoder.jp/contests/abs/tasks/abc083_b)

```io
ketawa := method(num,
  num asString asList map(asNumber) sum
)
l := File standardInput readLine split
n := l at(0) asNumber
a := l at(1) asNumber
b := l at(2) asNumber
result := 0
for(i, 1, n,
  w := ketawa(i)
  if(a <= w and w <= b, result = result + i)
)
result println
```
`ketawa`は数字の各桁の和を求めるメソッドです。いい感じにメソッドチェーンがつながって気持ちいいですね。

結果： AC / 0.59 s, 6296 kB
<details><summary>個別ケース結果</summary><div>5 s1: 0.06 s, 5988 kB
5 s2: 0.04 s, 5988 kB
5 s3: 0.04 s, 5992 kB
5 01: 0.59 s, 6280 kB
5 02: 0.23 s, 6292 kB
5 03: 0.56 s, 6292 kB
5 04: 0.59 s, 6292 kB
5 05: 0.50 s, 6288 kB
5 06: 0.53 s, 6284 kB
5 07: 0.56 s, 6296 kB
5 08: 0.48 s, 6288 kB

</div></details>

## 6. [ABC 088 B - Card Game for Two](https://atcoder.jp/contests/abs/tasks/abc088_b)

```io
readln := method(
  File standardInput readLine
)
n := readln asNumber
lst := readln split map(asNumber) sort reverse
alice := 0
bob := 0
for(i, 0, n - 1,
  if(i % 2 == 0,
    alice = alice + lst at(i),
    bob = bob + lst at(i)
  )
)
(alice - bob) println
```

listの各要素に処理を加え、戻り値のリストを得ることができる"高階関数"[^koukai]、`map`も存在します。

[^koukai]: 実際の処理としては各要素に、引数に与えた「メッセージ」を送っているだけなので関数型言語のように関数オブジェクトを扱っているわけではありません。

結果： AC / 0.06 s, 6012 kB
<details><summary>個別ケース結果</summary><div>6 ex1: 0.06 s, 6004 kB
6 ex2: 0.03 s, 6008 kB
6 ex3: 0.04 s, 6012 kB
6 random: 0.04 s, 6008 kB
</div></details>

## 7. [ABC 085 B - Kagami Mochi](https://atcoder.jp/contests/abs/tasks/abc085_b)

```io
readln := method(
  File standardInput readLine
)
n := readln asNumber
lst := list()
for(i, 0, n - 1,
  lst push(readln asNumber)
)
lst unique size println
```
`list`オブジェクトの`unique`メソッドは重複を取り除いたリストを返します。

結果： AC / 0.04 s, 5992 kB
<details><summary>個別ケース結果</summary><div>7 ex1: 0.04 s, 5988 kB
7 ex2: 0.04 s, 5992 kB
7 ex3: 0.04 s, 5984 kB
7 random: 0.04 s, 5988 kB
</div></details>

## 8. [ABC 085 C - Otoshidama](https://atcoder.jp/contests/abs/tasks/abc085_c)

```io
l := File standardInput readLine split
n := l at(0) asNumber
y := l at(1) asNumber
result := "-1 -1 -1"
for(i, 0, n,
  for(j, 0, n - i,
    if(10 * i + 5 * j + n - i - j == y / 1000,
      result = i asString .. " " .. j asString .. " " .. (n - i - j) asString
    )
  )
)
result println
```
$O(N^2)$なので間に合う想定の解なのですが、Io自体の速度の問題でsample4では12秒もかかってしまいました。

結果： TLE / 11.79 s, 5992 kB
<details><summary>個別ケース結果</summary><div>8 ex1: 0.04 s, 5988 kB
8 ex2: 0.03 s, 5980 kB
8 ex3: 2.81 s, 5992 kB
8 ex4: 11.79 s, 5988 kB
</div></details>

仕方がないので$O(1)$の解法で解きました。[参考](https://ark4rk.hatenablog.com/entry/2018/01/08/201801)

```io
l := File standardInput readLine split
n := l at(0) asNumber
y := l at(1) asNumber
t := (y - 1000 * n) / 1000
a := t % 4
b := (t - 9 * (t % 4)) / 4
kmin := list((- a / 4) ceil, ((a + b - n) / 5) ceil) max
kmax := (b / 9) floor
if(kmin <= kmax,
  (4 * kmin + a) asString .. " " .. (-9 * kmin + b) asString .. " " .. (n - 4 * kmin - a + 9 * kmin - b) asString,
  "-1 -1 -1") println
```

結果： AC / 0.04 s, 6012 kB
<details><summary>個別ケース結果</summary><div>8_2 ex1: 0.04 s, 6012 kB
8_2 ex2: 0.04 s, 6004 kB
8_2 ex3: 0.04 s, 6008 kB
8_2 ex4: 0.04 s, 6012 kB
</div></details>

## 9. [ABC 049 C - Daydream](https://atcoder.jp/contests/abs/tasks/arc065_a)
この問題では eraser→erase→dreamer→dream の順で置換しすると判定ができます。置換があれば一番簡単なのでまずはこれで解いてみます。

```io
if(File standardInput readLine asMutable replaceSeq("eraser", "!") replaceSeq("erase", "!") replaceSeq("dreamer", "!") replaceSeq("dream", "!") replaceSeq("!", "") == "", "YES", "NO") println
```
そのままの文字列はImmutableSequenceなので`replaceSeq`が使えません。`asMutable`でMutableば文字列に変換します。

結果： AC / 0.18 s, 6088 kB
<details><summary>個別ケース結果</summary><div>9 subtask0_0: 0.04 s, 5980 kB
9 subtask0_1: 0.03 s, 5980 kB
9 subtask0_2: 0.04 s, 5984 kB
9 subtask1_0: 0.14 s, 6080 kB
9 subtask1_10: 0.15 s, 6084 kB
9 subtask1_11: 0.17 s, 6088 kB
9 subtask1_12: 0.17 s, 6084 kB
9 subtask1_13: 0.17 s, 6084 kB
9 subtask1_14: 0.09 s, 6084 kB
9 subtask1_15: 0.12 s, 6084 kB
9 subtask1_1: 0.12 s, 6080 kB
9 subtask1_2: 0.04 s, 6080 kB
9 subtask1_3: 0.17 s, 6080 kB
9 subtask1_4: 0.17 s, 6076 kB
9 subtask1_5: 0.18 s, 6080 kB
9 subtask1_6: 0.17 s, 6080 kB
9 subtask1_7: 0.17 s, 6076 kB
9 subtask1_8: 0.17 s, 6080 kB
9 subtask1_9: 0.17 s, 6080 kB
</div></details>

公式解説の通りに、後ろから順に判定していく解法もあります。

```io
s := File standardInput readLine
len := s size
i := len
flag := true
while(i > 0,
  if("erase" == s exSlice(i - 5, i)) then(
    i = i - 5
  ) elseif("eraser" == s exSlice(i - 6, i)) then(
    i = i - 6
  ) elseif("dream" == s exSlice(i - 5, i)) then(
    i = i - 5
  ) elseif("dreamer" == s exSlice(i - 7, i)) then(
    i = i - 7
  ) else(
    flag = false;
    break
  )
)
if(flag, "YES", "NO") println
```

部分文字列は`exSlice`で取得します。`slice`も存在しますがdeprecatedだそうです。

結果： AC / 0.07 s, 6248 kB
<details><summary>個別ケース結果</summary><div>9 subtask0_0: 0.04 s, 5980 kB
9 subtask0_1: 0.04 s, 5984 kB
9 subtask0_2: 0.04 s, 5980 kB
9 subtask1_0: 0.07 s, 6216 kB
9 subtask1_10: 0.07 s, 6224 kB
9 subtask1_11: 0.06 s, 6248 kB
9 subtask1_12: 0.04 s, 6220 kB
9 subtask1_13: 0.07 s, 6248 kB
9 subtask1_14: 0.06 s, 6248 kB
9 subtask1_15: 0.07 s, 6220 kB
9 subtask1_1: 0.06 s, 6216 kB
9 subtask1_2: 0.07 s, 6216 kB
9 subtask1_3: 0.06 s, 6220 kB
9 subtask1_4: 0.06 s, 6216 kB
9 subtask1_5: 0.06 s, 6216 kB
9 subtask1_6: 0.06 s, 6216 kB
9 subtask1_7: 0.06 s, 6220 kB
9 subtask1_8: 0.06 s, 6212 kB
9 subtask1_9: 0.06 s, 6220 kB
</div></details>

## 10. [ABC 086 C - Traveling](https://atcoder.jp/contests/abs/tasks/arc089_a)

```io
readln := method(
  File standardInput readLine
)
n := readln asNumber
preT := 0
preX := 0
preY := 0
flag := true
for(i, 1, n,
  l := readln split;
  t := l at(0) asNumber;
  x := l at(1) asNumber;
  y := l at(2) asNumber;
  dt := t - preT;
  dl := (x - preX) abs + (y - preY) abs;
  if(dl > dt or dl % 2 != dt % 2, flag = false)
)
if(flag, "Yes", "No") println
```

この問題でも制約を超えてしまいました。
頑張って並列化すれば速くなるんじゃないかとも思ったんですが、どうも入力の読み込みにほとんどの時間がかかっているようです。~~IoなのにIOが遅い~~ こればっかりはちょっと手がつけられないので諦めました……

結果： TLE / 3.06 s, 6184 kB
<details><summary>個別ケース結果</summary><div>10 0_000: 0.04 s, 5996 kB
10 0_001: 0.06 s, 5980 kB
10 0_002: 0.06 s, 6000 kB
10 1_003: 0.04 s, 5992 kB
10 1_004: 3.06 s, 6108 kB
10 1_005: 3.00 s, 6132 kB
10 1_006: 2.96 s, 6184 kB
10 1_006: 3.00 s, 6524 kB
10 1_007: 0.50 s, 6184 kB
10 1_008: 0.03 s, 6000 kB
10 1_009: 0.67 s, 6188 kB
10 1_010: 0.06 s, 5996 kB
10 1_011: 0.42 s, 6184 kB
10 1_012: 0.04 s, 6416 kB
10 1_012: 0.07 s, 6420 kB
</div></details>

# まとめ
ちょっと遅いですがなかなかおもしろい言語です。
競プロではなかなか使う機会がありませんが、Ioは非同期処理がとても得意です。（例えばメッセージに`@`をつけるだけでFutureオブジェクトを生成し、オブジェクトをアクターとするのでとても簡単に書けます。）
プログラミングの基礎を学ぶ言語としては大変ポテンシャルのある言語なんじゃないかと思います。

惜しむらくは異常にググラビリティが低いこと、そして流行ったのがそこそこ昔（2000年代初頭）なため、当時あった日本語文献もほぼ散逸してしまい調べるのがとても大変なことです。
本記事も 『7つの言語 7つの世界』（オーム社、B. A. Tate著、まつもとゆきひろ 監訳、田和勝 訳）と「[Rubyist のための他言語探訪 【第 3 回】 Io](https://magazine.rubyist.net/articles/0010/0010-Legwork.html)」を頼りに公式ドキュメントをひーこら読みながら書きました（公式ドキュメントもそんなに詳しくない）。

AtCoderには無いけど[AnarGolfにはジャッジがある](http://golf.shinh.org/version.rb)のでやってみてください。

<!--
参考にしたかった記述
https://sumim.hatenablog.com/entry/20091007/p1
https://twitter.com/hotchpotch/status/857008337895817216
https://twitter.com/lettas0726/status/129872950911438848
https://twitter.com/iolanguage
-->