これまで
- ICPC2021: seica is gone
- ICPC2022: Maximum-goodlife9
- ICPC2023: Maximum-executive
- ICPC2024: executive is deprived
- ICPC2025: Maximum Masters
として 5 回出場してきました...!
ギリギリ早生まれ (1/1) なので一応年齢制限はクリアしているものの、コロナ禍特例は今年は適用されず、 5 回制限に引っ掛かり今年度はコーチとして参加することになりました!
当日まで
参加チーム募集
例年 Maximum 内でメンバーを募集していて、今年は 24 人参加という結果になった。
もともとコーチ 9 割・選手 1 割の心づもりでいて、 人数合わせ かつ 出場できる なら選手でいこうと考えていた。
5/19 23:59、募集終了。 募集結果が mod 3 = 0 になってうれしいので、無事 (?) コーチとして参加することに。
5/30、参加登録開始。参加ルールを読むと、コロナ禍特例が廃止されている。
結局選手で参加できないやんけ! mod 3 = 0 になってくれてほんとによかった。
今年度は ICPC 8 チーム参加予定っぽい?!
(そもそも出られたのか不明だけど) 人数合わせの必要がなくなり、コーチとして参加することにしたので jag-icpc.org/?Join をする!
コロナ特例ないらしいので、いずれにせよ出られなかった模様
JAG Join
5/19 23:59 の募集終了後、いよいよ jag-icpc.org/?Joinをした。
入会方法
入会の意思を固めたという方は
- 入会希望である旨
- 氏名 (本名)
- (必要に応じてハンドルネーム)
- 最近まで参加していた元参加者の場合はチーム名・大学名・学年 / その他の方は現在の所属
- メーリングリスト受信用 Gmail アドレス
- JAGで担当したいこと: 問題作成・テスター / 現地スタッフ/ 事務スタッフ / メーリングリストの受信のみ
をご記入の上、以下のメールアドレスまでご連絡ください。
下記の内容で特に力になれる・興味がある物があればアピールお願いします。
と書いてあったので、以下の内容を送信する。
さすがに深夜に送るのはよくないので、 10:00 にスケジュール設定をした。
ICPC JAG ご担当者様
お世話になります。 xx と申します。
選手としての ICPC 引退を機に、今度は運営側としてプログラミングコンテスト界を盛り上げるお手伝いがしたいと思い、入会を希望いたしました。入会にあたり、必要な情報を以下の通り送付いたします。
- 氏名: xxx
- ハンドルネーム: Asa / a01sa01to
- 所属: 埼玉大学大学院 M2 (元 Maximum Masters)
- メーリングリスト受信用アドレス: xxx
- 希望する担当業務: 現地スタッフ / 事務スタッフ
私は埼玉大学のプログラミングサークル「Maximum」に所属しており、 AtCoder では青コーダーとして活動しています。
問題原案の作成については自信はありませんが、サークル活動を通して JAG の仕事内容にある以下の業務を経験しています。
- ジャッジシステムの運用・ Rime の開発: サークル内での DOMjudge のホストやサーバー保守を行っているほか、 Maximum-Cup 2024 で Rime を使用したことがあります。
- 生中継: サークル内のイベント等で、 YouTube ライブの配信実務に携わったことがあります。
コンテストや地区大会の運営において、現地スタッフや事務スタッフとして少しでもお力添えできればと考えております。
なお、今年度はコーチとしてICPCに関わる予定ですが、選手としての出場予定はございません(加入資格は満たしています)。以上、どうぞよろしくお願いいたします。
5/23 返信が返ってきて、入会完了。
JAG の Discord に入ってみると、送ったメールがチャンネルに晒上げられており、恥ずかしい。 (メールを見逃さないという意味では良い運用ではある)
少しチャンネルを遡ってみると、本当に「1 - 6」+ α しか書いてないメールが多く、めちゃくちゃ気合が入ってる人みたいになってさらに恥ずかしい。
DOMjudge 構築
Maximum にサーバーが立っているので、これを使って練習のために DOMjudge を構築することにした。
DOMjudge は Docker Image としても動くので、大きく環境を汚さなくできて簡単。
...と思ったがこのサーバー、 Rootless Docker で動いていて、 judgehost で使われている cgroup が使えないことが判明。
仕方がないので、 Rootful Docker を生やして judgehost だけ Rootful で動かすことにした。
加えて、 Maximum では IdP を自作しており、 OpenID 対応の OAuth 2.0 の認証サーバーも作っているので、 DOMjudge の認証をこの IdP に任せることにした。
DOMjudge のドキュメントを見てみると、 Apache で mod_auth_openidc を使うことが想定されているようなので、これを使うことにした。
全体のコードとしては以下。 必要ならご自由にお使いください~
以下ファイルを同一ディレクトリに配置すれば行けるはず?
rootless.compose.yamlservices: db: image: mariadb:12.2.2 container_name: domjudge-db command: - --max-connections=1000 - --max-allowed-packet=512M - --innodb_log_file_size=1G - --innodb_snapshot_isolation=OFF - --log-error volumes: - mysql_data:/var/lib/mysql environment: - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} - MYSQL_USER=${MYSQL_USER} - MYSQL_PASSWORD=${MYSQL_PASSWORD} - MYSQL_DATABASE=${MYSQL_DATABASE} restart: unless-stopped domserver: image: domjudge/domserver:latest container_name: domjudge-web depends_on: - db volumes: - ./security.yaml:/opt/domjudge/domserver/webapp/config/packages/security.yaml:ro environment: - MYSQL_HOST=db - MYSQL_USER=${MYSQL_USER} - MYSQL_PASSWORD=${MYSQL_PASSWORD} - MYSQL_DATABASE=${MYSQL_DATABASE} - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} - CONTAINER_TIMEZONE=${TIMEZONE} restart: unless-stopped apache: build: context: . dockerfile: apache.dockerfile container_name: domjudge-apache depends_on: - domserver ports: - "12345:80" # 適当なポート番号 volumes: - ./httpd.conf:/usr/local/apache2/conf/httpd.conf:ro volumes: mysql_data:rootful.compose.yamlservices: judgehost-0: image: domjudge/judgehost:latest container_name: domjudge-judge-0 privileged: true cgroup: host network_mode: host volumes: - /sys/fs/cgroup:/sys/fs/cgroup:rw environment: - CONTAINER_TIMEZONE=${TIMEZONE} - DOMSERVER_BASEURL=${DOMSERVER_BASEURL} - JUDGEDAEMON_USERNAME=judgehost - JUDGEDAEMON_PASSWORD=${JUDGEDAEMON_PASSWORD} - DAEMON_ID=0.env(example)TIMEZONE="Asia/Tokyo" MYSQL_ROOT_PASSWORD="foo" MYSQL_USER="domjudge" MYSQL_PASSWORD="bar" MYSQL_DATABASE="domjudge" DOMSERVER_BASEURL="http://localhost:12345" JUDGEDAEMON_PASSWORD="judgehost"apache.dockerfileFROM httpd:2.4.67-trixie RUN apt-get update && \ apt-get install -y libapache2-mod-auth-openidc && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* EXPOSE 80 CMD ["httpd-foreground"]httpd.confServerRoot "/usr/local/apache2" Listen 80 ServerName https://domjudge.example.com # 必要モジュールの読み込み LoadModule mpm_event_module modules/mod_mpm_event.so LoadModule authn_core_module modules/mod_authn_core.so LoadModule authz_core_module modules/mod_authz_core.so LoadModule authz_user_module modules/mod_authz_user.so LoadModule unixd_module modules/mod_unixd.so LoadModule log_config_module modules/mod_log_config.so LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_http_module modules/mod_proxy_http.so LoadModule headers_module modules/mod_headers.so # ユーザー・グループ設定 User www-data Group www-data # ログ設定 ErrorLog /proc/self/fd/2 LogLevel warn <IfModule log_config_module> LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined LogFormat "%h %l %u %t \"%r\" %>s %b" common CustomLog /proc/self/fd/1 common </IfModule> # ========== OIDC モジュールの設定 ========== # # ref: https://github.com/OpenIDC/mod_auth_openidc LoadModule auth_openidc_module /usr/lib/apache2/modules/mod_auth_openidc.so # ----- プロバイダ設定 ----- # OIDCProviderMetadataURL https://idp.example.com/.well-known/openid-configuration OIDCClientID client_id OIDCClientSecret client_secret OIDCScope "openid profile" # ----- セッション管理 ----- # # Callback URL をどこにするか OIDCRedirectURI https://domjudge.example.com/redirect_uri # ログアウト後どこにリダイレクトするか OIDCDefaultLoggedOutURL / # セッション暗号鍵 OIDCCryptoPassphrase "some secret passphrase" # 無操作時タイムアウト: 1h (sec) OIDCSessionInactivityTimeout 3600 # セッションの最大保持期間: 1d (sec) OIDCSessionMaxDuration 86400 # State Cookie の最大数を 7 に制限し、超過時は古いものを削除する (true) # Cookie 数が多すぎると 503 になることがあるため OIDCStateMaxNumberOfCookies 7 true # ----- DOMjudge との連携 ----- # # preferred_username をユーザー名として DOMjudge に渡す OIDCRemoteUserClaim preferred_username # HTTP ヘッダでユーザー名を渡す、 none = エンコードなし (base64 などはしない) OIDCPassClaimsAs headers none # X-Remote-User ヘッダにユーザー名を渡す OIDCAuthNHeader X-Remote-User # ----- Reverse Proxy 設定 ----- # ProxyPreserveHost On ProxyPass / http://domserver:80/ ProxyPassReverse / http://domserver:80/ <Location /> AuthType openid-connect Require valid-user # DOMjudge 側で認証判断してくれる + DOMjudge 通常ログインもできるようにしたいので、 OIDC 未認証でも通す OIDCUnAuthAction pass </Location> <Location /login> # Login は OIDC に飛ばしたい OIDCUnAuthAction auth # ただし、 ?manual をつけると DOMjudge のログイン画面に行くようにする # POST も DOMjudge に行くようにする (ログインフォームの送信) OIDCUnAuthAction pass "%{QUERY_STRING} == 'manual' || %{REQUEST_METHOD} == 'POST'" </Location> <Location /logout> # DOMjudge 側で logout した後、 OIDC も logout させるためのリダイレクト # ref: https://github.com/OpenIDC/mod_auth_openidc/wiki#9-how-do-i-logout-users Header unset Location Header always set Location "https://domjudge.example.com/redirect_uri?logout=" </Location>security.yaml(DOMjudge のデフォルトから L72-75 を追加)# To get started with security, check out the documentation: # https://symfony.com/doc/current/security.html security: role_hierarchy: ROLE_JURY: [ROLE_CLARIFICATION_RW, ROLE_API, ROLE_API_READER, ROLE_API_SOURCE_READER] ROLE_ADMIN: [ROLE_JURY, ROLE_JUDGEHOST, ROLE_API_WRITER] ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH] # https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords password_hashers: App\Entity\User: algorithm: "bcrypt" cost: 7 providers: domjudge_db_provider: entity: class: App\Entity\User property: username firewalls: # NOTE: If you change anything in this section, or move the authenticators around # NOTE: make sure to update the $stateless_fw_contexts variables in each guard authenticator # NOTE: Otherwise they may not be enabled. # disables authentication for assets and the profiler, adapt it according to your needs dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false # SEE NOTE ABOVE IF CHANGING ANYTHING IN THIS SECTION # API does Basic Auth and IP address auth api: pattern: ^/api context: domjudge provider: domjudge_db_provider user_checker: App\Security\UserChecker entry_point: App\Security\DOMJudgeIPAuthenticator # SEE NOTE ABOVE IF CHANGING ANYTHING HERE custom_authenticators: - App\Security\DOMJudgeIPAuthenticator - App\Security\DOMJudgeBasicAuthenticator # Provides prometheus metrics metrics: pattern: ^/prometheus/metrics context: domjudge provider: domjudge_db_provider stateless: true user_checker: App\Security\UserChecker entry_point: App\Security\DOMJudgeIPAuthenticator # SEE NOTE ABOVE IF CHANGING ANYTHING HERE custom_authenticators: - App\Security\DOMJudgeIPAuthenticator - App\Security\DOMJudgeBasicAuthenticator # rest of app does form_login main: pattern: ^/ context: domjudge provider: domjudge_db_provider user_checker: App\Security\UserChecker entry_point: App\Security\DOMJudgeXHeadersAuthenticator custom_authenticators: - App\Security\DOMJudgeXHeadersAuthenticator - App\Security\DOMJudgeIPAuthenticator form_login: login_path: login check_path: login enable_csrf: true use_referer: true # ref: https://www.domjudge.org/docs/manual/9.0/config-advanced.html#using-remote-user remote_user: user: HTTP_X_REMOTE_USER provider: domjudge_db_provider logout: path: logout target: /public access_control: - { path: ^/$, roles: PUBLIC_ACCESS } - { path: ^/markdown-preview, roles: IS_AUTHENTICATED_FULLY } - { path: ^/login, roles: PUBLIC_ACCESS } - { path: ^/register, roles: PUBLIC_ACCESS } - { path: ^/public, roles: PUBLIC_ACCESS } - { path: ^/api, roles: PUBLIC_ACCESS } - { path: ^/, roles: IS_AUTHENTICATED_FULLY }
さらに、 DOMjudge のコンテスト準備をする。
各自練習に加え、サークルとして 4 回分時間をとったので、 ICPC2022 - 2025 Prelim を収録。
テストケースとかを一つずつやるのは面倒なので、 DOMjudge で import できる形式に変換しておいた。
saitamau-maximum/cp-judge-problems こちらもご自由にどうぞ
チーム登録
コーチになったので、チーム登録の任務が発生する。
6/2 以降、各自 ICPC アカウントの登録をしてもらうとともにチーム決めをしてもらう。
6/11 に全員が登録の確認できた + チーム情報も出そろったので、チーム登録を行う。
見ればわかるような作りにはなっていたが、念のため icpc.jp で公開されている情報をもとに進めていく。
全情報を入れ 3 重くらいチェックし、登録ボタンを押すも、一向に進む気配がない。
別タブで Dashboard にアクセスしても、チームが表示されない。
少し怖かったが、リロードして再入力し登録ボタンを押すと、今度は数秒で完了した。 一体なんだったんだ。
監督員には、自分のメールアドレスを伝えて監督員登録をしてもらうよう伝える。
コーチのメールアドレスで一括登録できるのは便利。
6/16、チーム登録完了メールが実行委員会から届く。
が、 1 チームだけ + がチーム名に含まれており、差し戻しを食らった。
すぐにチームに連絡を取り、 plus に変更の上、差し戻しメールに返信をした。
追加情報登録も各自済ませるように連絡。
みんな対応が少し遅くて不安になったが、何とか締切前日までに全員が対応完了。 これでチーム登録は完了。
無事全チーム Accepted となっていることを確認した。
参加チームは以下 8 チーム。
- Maximum Merinchan
- Maximum Apollon Infinity
- YAKINIKU
- YTTplus
- syosin daizi
- Maximum Chicken
- KARUBI
- Maximum Quorum
どこか 1 チームでも予選通って横浜連れていってくれればうれしい。
AtCoder レート的には Merinchan (水緑緑) がトップだが、最近 inactive な B4 チームの YAKINIKU メンバーも ICPC2024 で惜しいところまで行っている。
あるいはほかのチームがダークホースとして予選通過するかもしれない。
いずれにせよ、本番が楽しみ。
模擬
JAG 模擬は、 JAG の Discord で観戦をしていた。
模擬の 1 週間くらい前に、 test run が行われていたようだが、 SECCON Beginners 2026 と被っており出れず。
SECCON Beginners の writeup をまとめつつ、観戦しながら軽く問題を見てみる。
A はよい。
B は 1 種類だけなら IMPOSSIBLE。 そうでなければソートし、ソート結果が元と一致すれば reverse するとよさそう。
C は、尺取りができそう。
D はめんどくさそう。 制約が小さいので、うまくやれば全探索できそうだな~とは思うが、めんどくさそう。
E はよくわからないが、メタ読みすると 2 冪をうまく使えと言われている。
F は DP 臭がする。 よく考えずスルー。
G 以降も軽く読んでスルー。
(↑ 提出してないので間違ってるかも)
Maximum からは Merinchan だけが参加し、 3 完。
1 人都合が合わず、 2 人での参加だったらしい。
C が嘘解法で思考ロックされたらしく、本番は気を付けてほしい。
当日、本番前
12 時少し前、大学に到着。そのまま学食でチキンケバブ丼を食べた。
その後、学内ローソンで差し入れとしてパイの実と明治ミルクチョコレートを購入し、宣伝ツイートをする。
埼玉大学からは、
Maximum Merinchan / Maximum Apollon Infinity / YAKINIKU / YTTplus / syosin daizi / Maximum Chicken / KARUBI / Maximum Quorum
の 8 チームが出ます!
自分はコーチをしてます、横浜に連れてってくれ〜
対戦よろしくお願いします!!!
13 時、会場開場。 ネットワーク設定をし、準備完了。
各チームも続々とセットアップを完了させていき、リハーサルを進めていく。
画面をチラ見すると、例年 P, Q, R, S の 4 問なのに T, U, V, W を加えた計 8 問になっている。
問題を見せてもらうと、 max を求めるやつに加え 2023 A, 2022 A, 2021 A, 2024 A, 2023 C, 2022 E, 2022 G が使われている。
多いのはいいことだが、なんでこんなに使われているんだ...
W (= 2022 G)、 13:40 時点で誰も解いてないし
そんな中、 ICPC 公式からこんなアナウンスが。
本日16:30から19:30まで、ICPC国内予選のコンテストが行われます。順位表を観戦サイト icpcsec.firebaseapp.com にて公開します。
なお、問題文についてですが、コンテスト終了後の公開とすることになりました。コーチの方にお送りしたメールの内容と異なりますが、ご了承ください。
埼玉大学では、競技ルール Q7 (コーチは監督員の裁量で印刷の手伝いをしてもよい) に基づき、監督員が印刷しつつコーチが印刷の手伝いをしようとしていた。
しかし、「問題文は本番後の公開」となったことで、コーチも監督員も問題文を見れなくない?と思った。
リハーサルで確認すると、問題文は DOMjudge 上で未ログイン状態で確認できるため、システムにアクセスすれば確認できそう。
だが、「コーチは本番中 DOMjudge にアクセス禁止」とされており、非常に困ってしまった。
監督員が一時離れてしまっていたので、何を思ったか審判団に連絡を取ってみる。 (帰ってきてから相談すればいいのに...)
監督員なら DOMjudge にアクセスでき印刷できるのか、あるいはチーム各自で印刷しないといけないのか、聞いてみた。
すぐに返信が来た。
どうやら監督員に問題文の URL が別途送られているらしく、それ経由で監督員がアクセスして印刷できる模様。 それ以外については監督員の裁量で、とのこと。
完全に確認不足・連携不足だった。 手間かけさせてしまって申し訳ない...
話し合った結果、想定通りの流れでいいよねとなる。
16:20 くらい、いろいろ説明して頑張ってね!と言う。
いざ本番!
16:30 開始!
両面印刷 10 枚 x 24 人 = 240 枚、さすがに時間がかかる。
問題配布をして、 16:57 席に戻る。
なんか J まであって驚愕なんだけど
この時点で Merinchan が C まで通していてえらい。
Merinchan 含め 5 チームが 2 完している。
D はペナが多そうで、大変そう。
17:03 YTTplus B, 17:06 YAKINIKU C, 17:22 Quorum C と着実に進んでいく。
その後あまり順位表に変動がない中、 17:54 Apollon が C 飛ばして D を通している。
これはどこがトップチームになるかわからなくなってきた!
トップの Merinchan が突破圏外になってしまう。 がんばれ~!!
KARUBI が 17:53 に B を通していた。 Chicken も 18:10 に C を通している。
B1 チームでここまで解けていてすごい。
そこから少し苦戦しているようにみえる。 途中で Quorum の席から何かがわかったような歓声が聞こえるも、何も提出がない。
18:45 くらいに Merinchan が E を通し、 103 位に。 しかしまだ圏外。
YAKINIKU も E を出すが、 WA。 終了後に話を聞くと、方針自体はあってそうだが実装が一部ミスってたっぽい。
19:00、 Merinchan が D を通した! 2 分後に YAKINIKU も D を通す。
だがまだ突破圏外。 正直厳しそう...
終了間際、 Merinchan が G に投げるも、通らず。
ここで時間切れ。 お疲れさまでした~
聞くと、未証明 DP でサンプルを試さずにお祈りで投げたが、バグり散らかしており 0 しか出力しなかったらしい。
諦めない精神大事。
おわり
お疲れさまでした~!
最終結果は以下の通り。
残念ながら、埼玉大学からは予選突破チームは出なかった。 厳しい...
が、 Merinchan が補充候補 4 位ではあるので、ワンチャンあるかも?
'23 の自分たち (Maximum-executive) が補充候補 3 位で結局補充されなかったという悔しい結果があるので、期待せずに待っておく。
ほとんどのチームは (初心者 + inactive) 揃いで 2 完以上できていて素晴らしい。
syosin daizi は、聞けばまだ競プロにあまり取り組んでいないメンバーだったらしく、伸びしろしかない。
来年に期待!

打ち上げ
去年と同じ店で打ち上げ。 今年も "デザートは別腹" を担当。
帰宅
11 時半ごろ帰宅。 給湯器が壊れたらしく、数年ぶりに "地獄のシャワー" を浴びる。 寒い。
データセットが公開されていたので、 Maximum サーバーの DOMjudge にインポートする。
この記事を書き上げて就寝。