見出し画像

日本情報オリンピックランク基準と予選Bランク

 日本情報オリンピック (JOI)は,高校2年生までの競技プログラマー日本一を決める大会です。今年度の JOI 2023/2024 は2024年2月4日(日)に本選競技をオンラインで開催し,日本一が決定しました(一般社団法人情報オリンピック日本委員会のプレスリリース)!

 JOI 2023/2024 は,国際情報オリンピック IOI 2024 エジプト大会の日本代表選手選抜を兼ねており,本選競技の成績優秀者が一同に集い IOI 2024 日本代表最終選考競技に臨みます(JOI 春季トレーニング)。このように,まだ IOI 2024 日本代表選手の選抜が残っていますが,今年度の JOI としての競技は本選で終了です。そこで,来年度,中学や高校の授業や課外活動で日本情報オリンピックを活用しようと思っている先生方向けに,日本情報オリンピックのランク基準について,一般社団法人情報オリンピックや有志が公開している情報などを整理してみました。また,最初のランクである予選Bランクについて,すこしだけ掘り下げてみました。

 日本情報オリンピックは,もちろん,高校2年生までの競技プログラマー日本一を決める大会ですし国際情報オリンピック日本代表選抜を兼ねていますので,本選や春季トレーニング中の競技はハイレベルなものです。ですが,一次予選は授業でプログラミングを始めた生徒が十分に挑戦できる競技です。また,二次予選もハイレベルな課題が多く出題されるものの次のステップとして考えることができます!

 本選や春季トレーニングの競技で使用できるプログラミング言語は C++ のみとなっていますが,AtCoder の協力で実施されている一次予選や二次予選では「情報」の教科書でも使われている Python や JavaScript で参加できます。この記事では,コード例を示す場合は Python を使用します。


1. 日本情報オリンピックの大会フォーマット

 まず,日本情報オリンピック (JOI) の大会フォーマットを確認しましょう。下の記事にも書きましたが,ここに抜粋しておきます。

  • 一次予選:80分・4問 X 3回(1回以上参加することで,一番良かった競技の成績が採用されます)

  • 二次予選:3時間・5問 X 1回

  • 本選:4時間・5問 X 1回

  • 春季トレーニング:5時間 X 4回(4回の競技成績の合計で IOI 日本代表選手が決まります)

図にすると,こんな感じになります。

最近の JOI のスケジュール

一次予選の競技成績で二次予選に進出できるかどうかが決まります。二次予選に進出すると,予選 B ランク以上が確定します。

2.予選ランク・本選ランクの基準

第23回日本情報オリンピック要項の 「予選」項には,一次予選に関して次のように記載されています。

JOI 一次予選では、4 題の課題に取り組みます。
JOI 一次予選の競技結果に基づき全参加者に「JOI 予選 B ランク」と「JOI 予選 C ランク」のいずれかを与えます。
繰り返しを含む基本的なプログラムを適切に書くことができる者をJOI 予選 B ランクとします。この意図に基づき、原則として、JOI 予選 B ランク基準点を一次予選 3 題分の配点である 300 点と定めます。

第23回日本情報オリンピック 要項 「予選」より

 1回の一次予選では80分で4問の課題に取り組み,各課題100点で合計400点満点です。

 また,第23回日本情報オリンピック要項の「予選」の項には,二次予選に関して次のように記載されています。

JOI 二次予選では、5題の課題に取り組みます。
競技結果に基づき全参加者に「JOI 予選 A ランク」か「JOI 予選 B ランク」のいずれかを与えます。
成績上位の者を JOI 予選 A ランクとします。JOI 予選 A ランクとなった有資格者は、JOI 本選に進出することができます。JOI 予選 A ランク基準点は、以下のJOI 本選進出者の決定方法 i で定めます。

第23回日本情報オリンピック 要項 「予選」より

JOI 本選進出者の決定方法 i も見てみましょう。

JOI 2023/2024 二次予選に参加した有資格者のうち、JOI 予選 A ランクとなった者
JOI 予選 A ランク基準点は、JOI 予選 A ランク者の総数が 160 名を超えない最大数となるように定める

第23回日本情報オリンピック 要項 「予選」 JOI 本選進出者の決定方法 i

つまり,一次予選で3問正解300点以上取れば予選 B ランク以上が確定し,二次予選で上位160名までに入ると予選Aランクとなります。次の表は,一次予選が80分で4つの課題に取り組むようになったこの3年間の JOI の概況です。

https://www.ioi-jp.org/problem_archive のリンク先にある情報から構成

 点数や人数だけでは分からないこともあるので,この3年間についてAOJ/AtCoder-JOI ( https://joi.goodbaton.com/ )の難易度を表にしてみました。

AOJ/AtCoder-JOI ( https://joi.goodbaton.com/ ) の難易度より構成

 一次予選でBランク以上を確定するには原則として1回の競技で3問以上正解(300点以上)と決まっています。一方,予選Aランクや本選Aランクの得点は,参加選手の得点状況によって変わってきます。JOI 2023/2024 では,予選Aランクの基準点は上述のように「JOI 予選 A ランク者の総数が 160 名を超えない最大数となるように」,本選Aランクの基準点は「JOI 本選 A ランク者の総数が 30 名を超えない最大数となるように」(第23回日本情報オリンピック 要項 「本選」の「JOI 春季トレーニング進出者の決定方法」)決まります。

 難易度表に赤の二重線が引いてある箇所があるかと思います。二次予選でも本選でもAランクとなるためには,二重線の上の課題までは満点をとることが必要そうです。この3年間の2次予選におけるAランク基準点は,217点,207点,240点です。課題 A と B で満点をとり,C や D や E で部分点を取ることで予選Aランクになりました。(この記事では,問題番号を 1, 2, … ではなく,AtCoder過去問ページに合わせて A, B, …で表記します。)この3年間の本選におけるAランク基準点は,300点,268点,279点です。300点の年度もありましたが,その年度に C で満点を取った選手は11名,D で満点を取った選手は10名,E で満点を取った選手はいませんでした。A と B の2問で満点を取り C 〜 E の複数の課題で部分点を取ることで本選Aランク基準点を超えた選手が少なからずいたようです。

 赤二重線のすぐ上とすぐ下の課題の難易度を見てみると,二次予選ではすぐ上が5か6ですぐ下は7,本選ではすぐ上が7ですぐ下は10ですね。本選に進出する(予選Aランクとなる)には,難易度6までの問題で満点を取ることが重要そうです。春季トレーニングに進出する(本選Aランクとなる)には,難易度7や8までの問題で満点を取ることが重要そうです。

 この段落では,明瞭な根拠はない私の推察を書かせてもらいます。ここ3年間の本選では,課題 B の難易度はいずれも7で,次の難易度は9か10でした。ですが,課題 B の難易度が7ではなく8となることが今後起きても不思議ではないと思っています。また,JOI 2020/2021 や JOI 2019/2020 まで遡ると,課題 C の難易度が9で本選Aランクとなるには A, B, C 3問で満点を取る必要がありました。一方,これらの年度の本選Aランクの人数目安は「約20名」でした。最近3年間の「30名を超えない最大」と比べると約10名少なく,その分本選Aランクは狭き門だったとも考えられます。そうすると,Aランク者数の目安などの条件が変わらなければですが,本選Aランクとなるのに満点を取りたい難易度の目安は7や8までのような気がしています。

 次の節で,公開情報から分かる予選Bランクのレベル感を説明します。予選Aランクのレベル感については,別の記事で紹介をしようと思います。一方,本選Aランクのレベル感は今の私には説明できません。ある事情があって,ここ5年ほどの 一次予選・二次予選・本選で難易度 5 と 6の課題を,最近,全部解いてみました(これがこの記事を書くきっかけになりました)。ですが,難易度 7 以上の課題にはまだ取り組めていません。いつか5年分の難易度7や8の課題をすべて解いたら,本選Aランクのレベル感の紹介記事を書くかもしれません。

3.予選Bランクのレベル感

 予選Bランクの基準は「繰り返しを含む基本的なプログラムを適切に書くことができる者」で,一次予選が80分で4つの課題に取り組むようになってからは,基準点は「原則として、JOI 予選 B ランク基準点を一次予選 3 題分の配点である 300 点」(第23回日本情報オリンピック 要項 「予選」より)です。ここで,一次予選の難易度表をもう一度見てみましょう。

AOJ/AtCoder-JOI ( https://joi.goodbaton.com/ ) の難易度より構成

 難易度 2 の問題が解ければ良さそうです。では,難易度 2 の問題ってどのような問題でしょうか?JOI 2023/2024 の一次予選で出題された課題1を例に考えていきましょう。

 なお,情報オリンピック日本委員会の過去問ページでこれまでに出題された課題を見ることができます。また,AtCoder の JOI 過去問ページで課題に取り組むこともできます。

JOI 2023/2024 一次予選第1回 概況
JOI 2023/2024 一次予選第2回 概況
JOI 2023/2024 一次予選第3回 概況

 課題 A はいずれも,いくつかの整数を標準入力から受け取り,受け取った整数に四則演算を施す課題です。条件分岐も繰り返し処理も必要ない課題ばかりですめ。次のコードは,第1回 A 果物の解答例です。

x = int(input())
y = int(input())
print(x + y + 3)

Python では,$${\mathsf{input}}$$ で標準入力から受け取ったものは文字列として扱われるので $${\mathsf{int}}$$ で整数型に変換する必要がありますね。 

課題 B では,条件分岐か繰り返し処理が必要とされる課題が出題されています。例えば,第2回 B 火曜日は,入力した整数を7で割った余りが2であるかどうか判定する処理を実現する課題でした。次のコードは,その解答例です。

x = int(input())
if x % 7 == 2:
    print(1)
else:
    print(0)

 課題 C では文字列が,課題 D では配列(リスト)が扱われることが多いです。Python では添字(インデックス)を使って文字列を配列的に扱えます。文字列や配列(リスト)への処理を,添字(インデックス)と繰り返しを適切に組み合わせることで実現できれば,解答できそうです。課題 D では少しひねりが加わっていることもあります。(難易度2と難易度3の違いでしょうか。)

 例えば,第1回 C ハミング距離は,同じ長さの文字列が2つ入力として与えられると,両者で文字が異なる位置を数える問題です。添字(インデックス)に対応する文字を比較し,異なっていればカウンターをインクリメントする処理を繰り返せば良いですね。$${\mathsf{for}}$$と$${\mathsf{range}}$$を使った基本的な繰り返し処理で実現できます。次のコードは,その解答例です。

n = int(input())
s = input()
t = input()
c = 0
for i in range(n):
    if s[i] != t[i]:
        c += 1
print(c)

予選Bランクのレベル感をまとめると次のようになるでしょうか。

  • 入力された整数や文字列を適切に変数に保存できる

  • 算術演算や比較演算やブール演算などの基本的な演算子を適切に扱える

  • $${\mathsf{if}}$$文を用いて基本的な条件分岐を実現できる

  • $${\mathsf{for}}$$ 文を用いて基本的な繰り返し処理を実現できる

    • 必要に応じて,$${\mathsf{for}}$$ と $${\mathsf{range}}$$ を組み合わせて処理を実現できる

  • 文字列やリストの基本操作ができる

  • 文字列やリストに対して,$${\mathsf{for}}$$ と組み合わせることで繰り返し処理を実現できる

  • 処理した結果を,課題の指示に従い表示できる

 いかがでしょうか。「情報Ⅰ」でプログラミングを学んだばかりの生徒でも十分挑戦できそうですね!

 ところで,300点ではなく400点を狙うには,課題 C と課題 D の両方に正解する必要があります。課題 D では,1行に複数の整数が空白を区切りとして書かれている入力を扱うことがあります。JOI 2023/2024 一次予選では,第1回の D と第3回の D がそのような課題でした。1行に書かれた複数の整数をリストに格納する方法は知っておいた方が良さそうですね。次のコードは,第3回 D 差の解答例です。

k = int(input())
n = int(input())
a = list(map(int, input().split()))
m = int(input())
b = list(map(int, input().split()))
c = 0
for i in a:
  for j in b:
    if i + k == j:
      c += 1
print(c)

 $${\mathsf{input}}$$で入力された文字列を$${\mathsf{split}}$$を使って分割します。それが,$${\mathsf{input().split()}}$$の部分です。これだけでは,分割後も文字列のままですので,$${\mathsf{int}}$$を使って整数に変換する必要があります。$${\mathsf{map}}$$を使うと,分割した各要素に$${\mathsf{int}}$$を施すことができます。ただし,$${\mathsf{map}}$$の戻り値は$${\mathsf{map}}$$オブジェクトになるので,$${\mathsf{list}}$$でリストに変換します。組み合わせると
$${\mathsf{list(map(int, input().split()))}}$$
となります。1行に書かれた数列をうまく整数の配列に格納できれば,後は処理の実現に集中できますね。


 上述のように,JOI の過去問は情報オリンピック日本委員会が過去問ページで公開しています。課題のライセンスは基本的に CC BY-SA です。また,AtCoder のJOI過去問ページで,過去問に取り組むことができます。JOI の過去問には,AOJ/AtCoder-JOI ( https://joi.goodbaton.com/ )の難易度で 1 の課題も 2 の課題も30問以上あります。難易度 3 の課題も20問ほどあります。初学者向けの演習題材にもなると思われます。

この記事が気に入ったらサポートをしてみませんか?