__________の ICPCアジア地区予選2011参戦記 No.3/3

4:48経過 【__________(ノーネーム)】 ABCDEFGIJ 9/10完

「何なのよ……これ……」
 あたしは、ただ呆然と、目の前の巨大な順位表を見つめていた。

「なん、で……?」
「…………」
 タマキも愕然としている。あのトウコでさえも、表情が強ばっているのが分かる。

 カズミを潰して、9完して、それで勝利確定だったはずなのだ。
 なのにどうして、今、あたしは、これまでで最大級に、“負け”を確信している?

 一体、なんで。


「どうして、【若葉(わかば)】が、あたしたちを抜いて、1位になってるのよぉぉぉぉぉ!」


 ふらふらと定まらない視線で、すっかり様相を変えてしまった順位表に、目を向ける。
 だが、何度見たところで、結果は同じ。
 絶望に覆われた順位表は、あたしたちに敗北の現実を突きつけるだけだ。



 現在の順位:
 1位 【若葉】 ABCDEFGIJ 9完 ペナルティ+1614
 2位 【__________】 ABCDEFGIJ 9完 ペナルティ+1615
 3位 【玉兎】 ABDEFIJ 7完 ペナルティ+861



 このコンテスト中、チーム若葉が、3位以内に入ってくることは、今まで1度もなかった。
 確かに序盤はそこそこの速さで正確に問題を通していたけれど、それだけだ。
 ついさっき順位表を見たときも、若葉の順位は、ブレインネクサスよりも下の、4完止まりだったはず。

 それが、どうして、9完。
 あたしたちを抜いて、9完。

「……サクヤちゃん! サクヤちゃん! しっかりして!」
「っ!」
 気がつくと、あたしの身体は、タマキに肩を掴まれてがくがく揺すられていた。
 ……どうやら、茫然自失だったあたしを、タマキが正気に戻してくれたみたいね。

「……サンキュ、タマキ。おかげで我に返れた」
「うん。でも、どうしてこんなことになっちゃんたんだろう……」
 タマキの言う、こんなこと。
 その原因は、少し冷静に考えてみれば明白だった。



「サブマリン戦術。あたしたちは若葉に、それをやられた」



 若葉は、ずっと4完で止まっていたんじゃない。ただ、問題を解いていたのに、それを提出(サブミット)しなかっただけだ。
 ABFDの4問を、ペナルティタイム+184で通した若葉は、その後の時間を使って、ちゃんと問題を解いていた。
 そして、溜まった5問のソースコードを、ノーネームのペナルティタイムを上回れるギリギリの時間で一気に提出した。
 +286×5=+1430。これに+184を足して、+1614。
 まさに、潜伏(サブマリン)戦術の名にふさわしい、見事な急浮上だ。

「くっそ……! 完全に計算外だった……!」
 一見すると、サブマリン戦術は、自分のチームのペナルティタイムを増やすだけで、何のメリットのない作戦のように見えるかも知れない。
 だが、それは大きな間違いだ。
 ICPCは、できるだけ高い成績を取る競技ではなく、少しでもいいから他のチームより高い成績を取る競技なのだ。
 たとえば、安全に100%7完できる戦術と、80%の確率で6完止まりだが、20%の確率で8完できる奇策があったとしよう。ここで、他のチームが高々6完しかできないと分かっていれば、何の迷いもなく安全策を取ることができる。
 ゆえに、他のチームの動向を知ることは、自分のチームの戦略を立てるうえで非常に重要になってくる。
 そして、普通なら、他のチームの動向は、順位表を眺めていれば大体掴むことができる。多少の誤差はあれど、大きく外すことはまずない。
 ただ1つ、サブマリン戦術という例外を除いては。

「どうするの、サクヤちゃん!? もう時間がないよ!」
 分かってる。全ては、カズミを潰したうえで9完できれば全てが終わるという間違った見積もりを立てたあたしの責任だ。
 若葉の作戦は、本当に見事としか言いようがない。
 あたしたちに潰されたカズミと、カズミを潰すためにかなり余計な時間を消費したあたしたち。
 両者が争っている間は巧妙に身を隠し、最後の最後で全ての利益をかっさらう。
 ああ……。もう、本当に、戦略家としては完敗だよ……!


 ――サクヤ先輩にそう思っていただけるなら、私たちの頑張りも無駄じゃなかったんだなって、そう思えます。


 ふと、視線を感じて振り向く。
 今まで注意を向けることもなかった、あたしたちの後ろ斜め後方の机。
 荻原(おぎはら)カエ、加藤(かとう)ケイコ、片平(かたひら)イカ
 チーム【若葉(わかば)】のメンバー3人が、そこにいる。


 ――先輩を騙すような形になってしまって、ごめんなさい。けど、私たちが勝つには、こうするしかなかったんです。

 ああ、分かってるよ。
 途中、もしあんたたちが目立った活躍を見せてたら、カズミは容赦なく若葉を潰しに行った。
 悪いとは思うけど、多分あたしだってそうしただろう。

 ――私たち3人が(イエロー)コーダーだっていうのも、本当は嘘なんです。3人とも、もうとっくに(レッド)になれる実力は持っている。ただ、今日この日のために、TopCoderに出場するのを止めていただけ。

 それも分かってる。
 サブマリン戦術は、誰にでもできる闘い方じゃない。
 潜伏している以上、サブミットの結果を見てのデバッグは一切行えない。
 いざ浮上ってときに、1つでもWAを出してしまえば、あたしたちにペナルティタイムで負けてジ・エンド。
 あたしらみたいに、“食道デバッグ”なんてものも無いのに、ここまで大胆な戦術を実行に移せるその正確無比なコーディング力と胆力は、あたしにはないものだ。尊敬する。
 あんたたちは、(レッド)の、それも上位に位置するプログラマーだ。それは保証するよ。

 ――2年前、まだまだひよっこだった私たちを、サクヤ先輩は優しく導いてくれました。そのとき、私たちは思ったんです。ああ、この人のようになりたいな、って。先輩のような、強くて、温かくて、そしてカッコいいコーダーに。サクヤ先輩は、ずっと私たち3人の憧れの存在だったんです。

 そう言ってもらえると、あたしも嬉しいけど。
 ちょっと恥ずかしいけど、悪い気はしない。

 ――1年前のICPCには、私たちなりに努力して臨んだつもりでした。努力して、国内予選を突破できるところまで行きました。でも、それで初めて分かったんです。先輩のチームとあたしたちの間にある、圧倒的な力の差が。アジア地区予選で大敗した日の夜は、正直、ちょっと泣いちゃいました。こんな人たちを目指そうだなんて、あたしたちは、なんて無謀なことを考えていたんだろう、って。

 でも、それで今のあんたたちがあるんでしょう?

 ――はい。それがきっかけになって、私たちは、覚悟を決めました。生半可な気持ちじゃ、サクヤ先輩の高みには届かない。スキルの1つも持たない私たち凡人が、高みに至るために、毎日毎日、考えて、練習して、闘って、反省して。ただひたすら、それの繰り返し。最初は全然成果が上がらなくて、何度もくじけそうになったけど。それでも、私たちは、ここまで来た。サクヤ先輩に、認めて欲しかったから。

 ああ、認めるよ。
 そんな姿を見せられて、誰が認めないなんて言えるかよ。

 ――ありがとうございます。その言葉だけで、私たちは救われます。……最後に、サクヤ先輩。先輩の、世界大会に行くっていう目標を、邪魔してしまって本当にごめんなさい。実を言うと、私たちは最初、+1616で浮上するつもりだったんです。先輩に次いで2位になれるなら、それで満足かな、って。

 …………。

 ――でも、駄目でした。直前になって、どうしても勝ちたい! って、思ってしまったんです。先輩に並ぶだけじゃ、満足できなくなって。先輩を超えたい、っていう想いが、抑えきれなくなって。気がついたら、浮上のタイミングを、早めていました。……先輩。私たちは、尊敬する先輩の姿に、自らの手で傷をつけてしまった大罪人です。許してくださいなんて言いません。どんな裁きだって甘んじて受けます。だから、それでも、できることなら、私たちのことを

 あのさあ、カエ。

 ――?

 その“先輩”って、一体誰のこと言ってんのよ。

 ――え? サクヤ先輩?

 あんたらの言う“憧れの先輩”ってのはさあ、ちょっと後輩に抜かれた程度で簡単に目標を諦めてしまうような、ヤワな野郎なわけ?
 はっ。だったらあたしとは仲良くなれそうにないわね。無理。絶対無理。生理的に受け付けないわ。

 ――え、いや、あの、先輩?

 命拾いしたわね、カエ。もしあんたたちが本当に+1616で浮上してたら、あたしはあんたたちを思いっきり全力でぶん殴ってたところよ。

 ――先輩、どうして……。

 見てなさい、とは言わないわ。
 今から汚いものをいっぱい見せるから、嫌なら目をつぶって震えていればいい。
 努力は必ずしも報われないし、作戦は必ずしも実らない。
 夢は必ずしも叶わないし、想いは必ずしも届かない。
 現実は、必ずしも思い通りにはならない。
 でも、とりあえずは、まあ、そうね。



 ――あんたらの思いあがった根性、このあたしが叩きなおしてやるから、覚悟しなさい。



 この間、約3秒。

「タマキ! トウコ! この勝負、勝つわよ!」
 無理やり意識を現実に引き戻す。
 さっきのやり取りで、俄然やる気が出てきたわ。

「おぉー! サクヤちゃんが本気だよぉー!」
「サクヤ。次の作戦は」
 今まであたしについてきてくれたこいつらのためにも、ここで折れるわけにはいかない。
 信念も、目標も、そして結果も、何もかもだ。

 チームメイト2人に向かって、あたしは、精一杯の悪い顔を浮かべながら、告げる。



「作戦? そんなものは無いわ。個人プレーの、力押しで行くわよ」



4:50経過 【__________(ノーネーム)】 ABCDEFGIJ 9/10完

「<領域拡張(フライオーバー)>、発動」

 鈴の音のような澄んだ耳鳴りが、あたしの身体の中を駆け巡る。
 何度やっても、慣れない感覚。けれど今は、この違和感を叩き伏せてコーディングするしか方法はない。

 コンテスト終了まで、残り10分。
 残されたわずかな時間の中で、H問題を通す。
 あの“最強最速の双子”ですら15分かかった問題を、それより5分短く解く。
 それしか、あたしたちが生き残る道はない。

 考えてみれば、これは、去年のアジア地区予選と全く同じ状況だった。
 約10分を残して9完するも、1位にいるのはペナルティタイムであたしたちを上回る【玉兎】。
 残された強実装の構文解析を通せずに、そのまま敗北した。

 同じ失敗を2度繰り返して負けるなんて、あたしのプライドが許さない。
 あたしを相手に、10分も猶予を与えることが一体どういうことなのか。
 きっちり教えてあげようじゃないの。

拡張(ダブル)! 視覚(ディスプレイ)! 拡張(ダブル)! 触覚(キーボード)!」

 これで、あたしの主観では、ディスプレイが2つに、キーボードが2つ。
 普段は扱いづらいスキルだけど、こんなときくらいは全力で活用させてもらう。

「まずは、関数プロトタイプ宣言!」

#include <stdio.h>
#include <ctype.h>
#include <string.h>

int fexpr(int r1,int c1,int r2,int c2);
int fterm(int r1,int c1,int r2,int c2);
int ffactor(int r1,int c1,int r2,int c2);
int fpowexpr(int r1,int c1,int r2,int c2);
int fprimary(int r1,int c1,int r2,int c2);
int ffraction(int r1,int c1,int r2,int c2);
int fdigit(int r1,int c1,int r2,int c2);

int vexpr[21][81][21][81];
int vterm[21][81][21][81];
int vfactor[21][81][21][81];
int vpowexpr[21][81][21][81];
int vprimary[21][81][21][81];
int vfraction[21][81][21][81]; 

char board[21][81];

 ある領域を評価するためのの関数(Function)と、ある領域が評価されたときの(Value)を表す変数。
 構造は極力シンプルに。
 実行速度が早くなくてもいい。多少の冗長さなら許容する。
 とにかく正確に、紛れやバグの出ないコーディングができるよう。
 全ての土台を、慎重に組み上げる。

「サクヤちゃん! あと8分だよ!」

 <領域拡張(フライオーバー)>の効果で、あたしは自分自身が、4つの目と4本の腕を持っている人間であるかのように感じられる。
 そのうち2つずつを、仮想のディスプレイAとキーボードAに。
 残った2つずつを、仮想のディスプレイBとキーボードBに。
 それぞれ割り当てて、並列コーディングを開始する。

<仮想ディスプレイ A>

bool allspace(int r1,int c1,int r2,int c2){
  for(int i=r1;i<r2;++i) {
    for(int j=c1;j<c2;++j) {
      if(board[i][j]!='.')return false;
    }
  }
  return true;
}
<仮想ディスプレイ B>

bool allspace_col(int r1,int r2,int c1){
  return allspace(r1,c1,r2,c1+1);
}

bool allspace_row(int c1,int c2,int r1){
  return allspace(r1,c1,r1+1,c2);
}

 空白地帯の判定関数は終了。
 デバッグやテストをしている時間は取れない。一発完動は大前提だ。

「サクヤ。残り7分」

 拡張領域での作業は、あたしの主観では、2つのパソコンに同時にそれぞれ別々のコードを打ち込んでいるようなものだ。
 だが現実では、あたしが2つのキーボードに打ち込んだ情報は統合され、1つのソースコードになって出力される。
 つまり、1つのソースを書き上げるのに、2つの仮想的なキーボード入力を同時に使用しているのと同じ。
 理論上には、コードが書き上がる速度は2倍。
 コードが書き上がるまでにかかる時間は、半分だ。

<仮想ディスプレイ A>

void shrink(int &r1,int &c1,int &r2,int &c2){
  while(r1<r2){
    if(allspace_row(c1,c2,r1))++r1;
    else break;
  }
  while(r1<r2){
    if(allspace_row(c1,c2,r2-1))--r2;
    else break;
  }
  while(c1<c2){
    if(allspace_col(r1,r2,c1))++c1;
    else break;
  }
  while(c1<c2){
    if(allspace_col(r1,r2,c2-1))--c2;
    else break;
  }
}
<仮想ディスプレイ B>

#define mod(x) ((((x)%2011)+2011)%2011)

int inv[2022];

int mypow(int x,int d){
  int ret=1;
  if(d==0)return 1;
  if(d%2==1)return mod(mypow(x,d-1)*x);
  ret=mypow(x,d/2);
  return mod(ret*ret);
}

int main(){
  for(int i=1;i<2011;i++)inv[i]=mypow(i,2009);
  for(;;){
    int rows,cols;
    scanf("%d ",&rows);
    if(rows==0)return 0;
    for(int i=0;i<rows;i++){
      gets(board[i]);
    }
    cols=strlen(board[0]);
    memset(vexpr,-1,sizeof(vexpr));
    memset(vterm,-1,sizeof(vexpr));
    memset(vfactor,-1,sizeof(vexpr));
    memset(vpowexpr,-1,sizeof(vexpr));
    memset(vprimary,-1,sizeof(vexpr));
    memset(vfraction,-1,sizeof(vexpr));
    printf("%d\n",fexpr(0,0,rows,cols));
  }
}

「ぐ……っ!」
 唐突に、脳を針で刺したような痛みが襲う。
 頭の中を貫かれたかのようなその鋭い激痛は、過剰な身体感覚が送り込まれてきた脳が、拒絶反応を起こしたことによるものだ。

能力(スキル)なんだから、その辺は都合良く何とかならないのかしら……っ!」
 いくら嘆いても、一度身についてしまったスキルの特性を変えることなどできるはずもない。

拡張(ダブル)! (ブレイン)っ!」
 たまらず脳そのものを2倍にする。
 それにより、頭蓋骨を開いて火箸を突っ込まれたような痛みは消えるも、その代わり身体が平衡感覚を全て失ってしまったかのように上手く動かない。動かせない。
 感覚を統合する受け皿を増やしたことによる、混乱。
 船酔いを20倍くらい酷くしたような、気持ち悪さが一挙に襲いかかってくる。

 残り4分50秒。
 だが、それでも、AとBのどちらか一方でもコーディング速度が落ちれば、待っているのは敗北。
 身体を休めるわけにはいかない。思考を止めるわけにはいかない。

<仮想ディスプレイ A>

#define HERE(x) (x)[r1][c1][r2][c2]

int fexpr(int r1,int c1,int r2,int c2){
  shrink(r1,c1,r2,c2);
  if(HERE(vexpr)!=-1)return HERE(vexpr);
  if(fterm(r1,c1,r2,c2)!=-2){
    return HERE(vexpr)=fterm(r1,c1,r2,c2);
  }
  for(int j=c1+1;j<c2-1;j++){
    for(int i=r1;i<r2;i++){
      if(board[i][j]=='+' || board[i][j]=='-'){
        if(allspace_col(r1,r2,j-1) && allspace_col(r1,r2,j+1) && allspace_col(r1,i,j) && allspace_col(i+1,r2,j)){
          int ret1=fexpr(r1,c1,r2,j-1);
          int ret2=fterm(r1,j+2,r2,c2);
          if(ret1!=-2 && ret2!=-2){
            if(board[i][j]=='+')return HERE(vexpr)=mod(ret1+ret2);
            else return HERE(vexpr)=mod(ret1-ret2);
          }
        }
      }
    }
  }
  return HERE(vexpr)=-2;
}
<仮想ディスプレイ B>

int fterm(int r1,int c1,int r2,int c2){
  shrink(r1,c1,r2,c2);
  if(HERE(vterm)!=-1)return HERE(vterm);
  if(ffactor(r1,c1,r2,c2)!=-2){
    return HERE(vterm)=ffactor(r1,c1,r2,c2);
  }
  for(int j=c1+1;j<c2-1;j++){
    for(int i=r1;i<r2;i++){
      if(board[i][j]=='*'){
        if(allspace_col(r1,r2,j-1) && allspace_col(r1,r2,j+1) && allspace_col(r1,i,j) && allspace_col(i+1,r2,j)){
          int ret1=fterm(r1,c1,r2,j-1);
          int ret2=ffactor(r1,j+2,r2,c2);
          if(ret1!=-2 && ret2!=-2){
            return HERE(vterm)=mod(ret1*ret2);
          }
        }
      }
    }
  }
  return -2;
}

 構文解析の問題は、大枠さえ組めれば、後は構文解析(パーサ)の機能を1つ1つ順に実装していくだけでいい。
 それぞれの機能は関数という形で並列に並べてある。実を言うならば、構文解析ほど並列コーディングに適したジャンルはない。

「サクヤちゃん! 残り3分10秒を切ったよっ!」

 タマキの声色からも、この最後の勝負に参加できない歯がゆさが伝わってくる。
 でも、<領域拡張(フライオーバー)>によって作り出した仮想のキーボードは、あたしの主観の中にしかない。
 加えて、能力発動中にもし誰かが現実(リアル)のキーボードを使って何かしらの情報を入力すれば、<領域拡張>の統合操作に矛盾が起きて、スキルそのものが破綻する。

 この領域で闘えるのは、正真正銘あたしだけ。
 最後までワガママなリーダーで、悪かったわね。

 でも、その代わり、この問題だけは、何があっても通すから。

<仮想ディスプレイ A>

int ffactor(int r1,int c1,int r2,int c2){
  shrink(r1,c1,r2,c2);
  if(HERE(vfactor)!=-1)return HERE(vfactor);
  if(fpowexpr(r1,c1,r2,c2)!=-2){
    return HERE(vfactor)=fpowexpr(r1,c1,r2,c2);
  }
  if(ffraction(r1,c1,r2,c2)!=-2){
    return HERE(vfactor)=ffraction(r1,c1,r2,c2);
  }
  if(c2-c1>=3){
    for(int i=r1;i<r2;i++){
      if(board[i][c1]=='-'){
        if(allspace_col(r1,i,c1) && allspace_col(i+1,r2,c1) && allspace_col(r1,r2,c1+1)){
          int ret=ffactor(r1,c1+2,r2,c2);
          if(ret!=-2){
            return HERE(vfactor)=mod(-ret);
          }
        }
      }
    }
  }
  return -2;
}
<仮想ディスプレイ B>

int fpowexpr(int r1,int c1,int r2,int c2){
  shrink(r1,c1,r2,c2);
  if(HERE(vpowexpr)!=-1)return HERE(vpowexpr);
  if(fprimary(r1,c1,r2,c2)!=-2){
    return HERE(vpowexpr)=fprimary(r1,c1,r2,c2);
  }
  for(int i=r1;i<r2;i++){
    if(fdigit(i,c2-1,i+1,c2)!=-2){
      if(allspace_col(r1,i,c2-1) && allspace_col(i+1,r2,c2-1)){
        int d=fdigit(i,c2-1,i+1,c2);
        int ret=fprimary(r1,c1,r2,c2-1);
        if(ret!=-2){
          return HERE(vpowexpr)=mypow(ret,d);
        }
      }
    }
  }
  return -2;
}

 残り1分15秒。

 くそ……! ペースが落ちてきてる……っ!

 2つの脳が混ざり合ってぐちゃぐちゃになってしまったかのようだ。
 体力が保たない。集中力が続かない。ただ意識を保つことがこんなにしんどいだなんて。

 しかも、ここに来て、脳の痛みが復活しやがった。
 やっぱり、どう工夫しようとオーバースペックであることに変わりはないのだ。
 鈍痛と疼痛が同時に襲ってくる。何もかもを投げ捨ててこの痛みから解放されたいという衝動が、隙あらばあたしの身体を支配しようとしてくる。

 マズい……このままじゃ、確実に……!

 だったら!

拡張(ダブル)! 触覚(マウス)っ!」

 ただでさえキーボードの操作だけで手一杯だった触覚を、一時的にとはいえマウスに回す。
 余計に脳の回線が乱れに乱れ、普通に立っていることさえ困難になる。
 だから、身体は捨てる。机に倒れかかるようにして、仮想の4つの目と4つの手だけに研ぎ澄ませた全神経を集中させる。

 範囲選択。コピー。そしてペースト。

 1つ1つの関数の構造には共通点が多い。
 だったら、毎回一から打ち込むよりも、コピーしたものを修正した方がわずかに早い!

<仮想ディスプレイ A>

int fprimary(int r1,int c1,int r2,int c2){
  shrink(r1,c1,r2,c2);
  if(HERE(vprimary)!=-1)return HERE(vprimary);
  if(fdigit(r1,c1,r2,c2)!=-2){
    return HERE(vprimary)=fdigit(r1,c1,r2,c2);
  }
  if(c2-c1>=5){
    for(int i=r1;i<r2;i++){
      if(board[i][c1]=='(' && board[i][c2-1]==')'){
        if(allspace_col(r1,i,c1) && allspace_col(i+1,r2,c1) && allspace_col(r1,i,c2-1) && allspace_col(i+1,r2,c2-1) && allspace_col(r1,r2,c1+1) && allspace_col(r1,r2,c2-2)){
          int ret=fexpr(r1,c1+2,r2,c2-2);
          if(ret!=-2)return HERE(vprimary)=ret;
        }
      }
    }
  }
  return -2;
}
<仮想ディスプレイ B>

int ffraction(int r1,int c1,int r2,int c2){
  shrink(r1,c1,r2,c2);
  if(HERE(vfraction)!=-1)return HERE(vfraction);
  
  for(int i=r1+1;i<r2-1;i++){
    bool allhyphen=true;
    for(int j=c1;j<c2;j++)if(board[i][j]!='-')allhyphen=false;
    if(allhyphen){
      int ret1=fexpr(r1,c1,i,c2);
      int ret2=fexpr(i+1,c1,r2,c2);
      if(ret1!=-2 && ret2!=-2)return HERE(vfraction)=mod(ret1*inv[ret2]);
    }
  }
  return -2;
}

 残り、20秒。
 なのに、組むべき関数は、あと1つだけ残っている。

「くっ、そぉぉぉぉぉぉぉぉぉ!!」

 腹の底から大声を捻りだして、もうほとんど麻痺して感じられなくなっていた拡張感覚を、無理やり引き戻す。

 頼む。あとたった5行なんだ。それさえ保ってくれれば、後は――――!

int fdigit(int r1,int c1,int r2,int c2){
  shrink(r1,c1,r2,c2);
  if(r2-r1==1 && c2-c1==1 && isdigit(board[r1][c1]))return (board[r1][c1]-'0');
  return -2;
}

 あと4秒。

 最後の1文字をタイプし終えたと自覚した瞬間、今まで辛うじて机に支えられて保っていたあたしの身体が、崩れ落ちて乾いた床の上に投げだされる。

 あと3秒。

 そんなあたしに、タマキが半泣きになりながら駆け寄って来るのが見える。
 一方でトウコは、あたしの方には目もくれず、コードが組み上がった瞬間、現実(リアル)のマウスに手を伸ばし、完成したテキストファイルをコンマ1秒でも早く提出するために動き出していた。

 あと2秒。

 そう、それで正解だよ、トウコ。
 ……でも、タマキも、ありがとう、な。

 あと1秒。

 意識がぶつ切りになって、<領域拡張(フライオーバー)>が強制的に途切れる。
 急に感覚の半分が消滅したことで、身体全体を形容しがたい喪失感のようなものが埋め尽くし、蹂躙し、そして。





 視界が、暗転する。





試合後

 また、あのときの夢を見た。



「秋葉サクヤ。この勝負、お前の負けだ」

 真っ黒なコートに身を包んだ長身の男が、抑揚を感じさせない声で、闘いの結末を告げる。

「……っ! はぁ……っ! 嫌だ……! あたしは、まだ、闘える……っ!」

 当時まだ10歳だったあたしには、ただ吠える以外に何もできることはなかった。
 それが、突然現れてあたしの日常を何もかもメチャクチャにした男に対する、精一杯の抵抗だった。

「喚くな、見苦しい。敗れた者には、何を望む資格もない。貴様は負けた。運命の歯車は、我が手の中にある」

「許さない……っ! お前だけは……絶対に……!」

「ほう。復讐を望むか。ならば、運命に抗ってみるか? 負けることは、死ぬことだ。その摂理を歪めてでも、生にしがみつこうとする小さき者よ。足掻け。足掻き続けたその先で、貴様の理想とする競技プログラマーの姿を掴んでみせよ」

「上等だ……! 待っていろ……。必ずお前を殺してやる……っ!」

「不可能だ、と言っておこう。だが、貴様がもし、競技プログラミングを以って運命の輪を捻じ曲げるに足る資格を持つ者だとすれば。……我は待とう。レーティング4000を超えた者だけが至ることのできる境地、黒の世界(Division 0)で」



 そしていつも、ここで夢は途切れる。







 目が覚めると、ベッドの上だった。


「痛ッ……!」
 身体を起こした途端、思い出したかのように激しい痛みが襲ってくる。
 頭がずきずきと軋むように痛い。酷使しすぎた脳が悲鳴を上げている。

「ここは……。ああ、そういやあたし、コンテスト終了と同時に気絶したんだっけ……」
 見慣れない部屋に寝かされているということは、おそらく、自分はコンテストのスタッフだか誰だかの手でここまで運ばれてきたのだろう。
 時計を確認すると、午後7時。倒れてから、丸々5時間近くも寝ていた計算になる。
「ったく。これだから、あたしの能力(スキル)はあんまり使いたくないのよね……」
 いくら一時的にコーディング速度を増すことができるとはいえ、並列コーディングの最中に味わう苦しみは、想像を絶するレベルだ。
 それでいて、下手をすれば今のようにぶっ倒れてしまうとは、メリットとデメリットが釣り合っていなさすぎる。使い所が難しいにも程がある。
 もっと使い勝手のいいスキルなんて、いくらでもあるだろうに。

「ま、今回はそれに助けられたわけだし、良しとしましょうか」
 そう呟いて、そして、ふと思い出す。
「あ、そういや、あたし、コンテストの結果知らないじゃん……」
 Hのコードを組み上げた瞬間、精根尽き果てて意識を失ってしまったが、よく考えるとあのコードが通ったのかどうか確認していない。
 あのときは、自分の書いたコードがどれだけ正確に動きそうかの判断が全くできないほどの極限状況下だった。
 通ったとしても、落ちたとしても、何らおかしくはない。

「……タマキかトウコに、訊いてみっか」
 コンテスト中はあれほど勝利への執念にとりつかれたようになっていたにも関わらず、今は不思議と気持ちが穏やかだ。
 おそらく、あの並列コーディングで、Acceptedにかける情熱的な感情のようなものを、一時的に全て燃やしつくしてしまったのだろう。
 今なら、どんな結果を聞いても素直に受け止められる気がする。

 携帯を取り出し、電話をかけようとしたところで、ギィ、と、少しサビついた扉が開く音がした。
「トウコ?」
 そこに立っていたチームメイトは、とことこと歩いてくると、あたしが寝ている隣のベッドに腰を下ろした。
 今ごろは閉会式(Closing Party)の真っ最中だろうに、あのトウコが立食パーティーを放り出してまであたしのお見舞いに来てくれたことに、不覚にも涙腺が緩みそうになる。
 とはいえまずは、結果を訊かねば。

「ねぇトウコ。コンテストの結果、どうだった?」
 単刀直入に、訊ねる。
 それに対して、トウコは、言いずらそうに俯きながら、ぽつり、と。
「……サクヤ、ごめん」
 ごめん、ということは、そういうことなのだろう。
「……はぁ。ま、覚悟はしてたけどね。あんな綱渡りみたいなコーディング、成功する方がどうかしてるわ」
 それがあたしの本心からの言葉だったかと言われれば、即答することはできない。
 でも、不思議と今のあたしは、全力を尽くしたんだから悔いはないなんて、そんな似合わない考えを自然と受け入れられているような、そんな気がするのだ。
「心から反省している。次こそは」
「次は、って、もう来年の話? そもそも、別にあんたの責任じゃないわよ」
「でも、私がもっとしっかりしていれば」
「あー、うるさい! あんた、あたしが湿っぽいの嫌いだっての知ってるでしょ? あたしたちが負けたのは、誰の責任でもない。しいて言うなら、みんなの責任。異論は認めない」

「……サクヤ、ありがとう」
 ゆっくりと頭を下げたトウコは、それから、おずおずとあたしに何かを差し出してきた。
 それは、プラスチック製の、比較的大きめのタッパーだった。中身は空。
 ただし、タッパーの内側には、茶色いソースらしきものが少し付着していて――。
「閉会式に出た料理を、サクヤにも食べさせてあげようと思い、この中に詰めた。一杯に詰める所まではうまくいったが、ここに来る途中で、少しくらいなら歩きながら食べてもいいかと考え、蓋を開けたはいいが……5メートルと保たなかった。心から反省している。でも、私の責任ではないとサクヤが言うのなら」
 殴った。
 グーで。
「な……っ! 残像だと!?」
「サクヤは甘い。1つ1つの動作が直線的すぎる」
 あたしの拳を避けたトウコは、重力を感じさせない動きでベッドから立ち上がると、いつものような無表情でこちらを見つめてきた。
「なお、閉会式の料理は、主に私が食べつくしたおかげで、現在、急遽追加で調理中。ゆえに、今私がここに来ていることに関して、サクヤが気に病む必要はない」
「ああそうだな! できることなら、3分前の愚かな自分をぶん殴ってやりたいわ!」
 こいつはこういう奴だって、今まで散々見てきたはずだろ、あたし!
 というか、あたし、ちゃんと“コンテストの結果”はどうだったかって訊いたよなぁ!?
 絶対分かってて言ってやがるだろ! あと前フリが長い!
「というわけで、これから私は立食パーティー(Food Challenge)の後半戦に向かう。こちらでも優勝してくるから、サクヤは私を信じて待っていて欲しい。“次こそは”、サクヤの分の料理を持って帰れるように善処する。では」
「ああとっとと行っちまいやがれこの野郎! あとその善処は、天丼になるのが目に見えてんだよ!」
 あっという間にドアを開けて走り去ってしまったトウコに、あたしの台詞が聞こえたかどうかは、定かではない。

 ……って、トウコ今、こちらで「も」、って言ったか?

 その疑問は、すぐに解けた。
 トウコと入れ違いになるようにして部屋に入ってきたタマキが、両手で持ち切れないくらいにでっかい金色のトロフィーを抱えていたからだ。


「サクヤちゃん! やったよ! わたしたち、アジア地区予選、優勝だよ!」


 その言葉を聞いて、あたしは。
「……あれ? サクヤちゃん、泣いてるの?」
「え? あたしが? そんなわけ……」
 指摘されて初めて、自分の頬を、つ……と流れ落ちる何かの存在に気づく。
 え、嘘だろ、おい。タマキじゃあるまいし、なんであたしが泣くんだよ。

「…………」
 改めて、冷静に自分の気持ちと向き合ってみて、分かった。
 ごめん。やっぱ、感情が燃え尽きたとか、嘘だったわ。

「やったぜタマキ超嬉しいぃぃぃぃぃぃぃぃぃぃぃぃぃぃぃぃぃぃぃ!!」
「サクヤちゃんサクヤちゃんサクヤちゃんサクヤちゃんサクヤちゃん!!」

 人目がないのをいいことに、思いっきり抱き合うあたしとタマキ。
 うおぉぉぉぉぉぉ! あのH通ったのか! 自分のことながら信じられねぇぇぇぇぇぇ!!

「いやっほぉぉぉぉぉぉぉぉぉぉい! ひょほぉぉぉぉぉぉぉぉぉぉ!!」
「サクヤちゃんサクヤちゃんサクヤちゃんサクヤちゃんサクヤちゃん!!」

 世界大会進出だぁぁぁぁぁぁぁぁぁぁぁ!! いぇやぁぁぁぁぁぁぁぁぁぁぁ!!


 ◆


 10分後。

「……こほん。それで、順位表の最終結果はどうなったの?」
 ひとしきり騒ぎまくった後、我に返ったあたしは、何事もなかったかのようにタマキに訊ねる。
「うん、これだよ。プリントアウトして、持ってきたんだ〜」


 最終結果:
 1位 【__________】 ABCDEFGHIJ 10完 ペナルティ+2014
 2位 【玉兎】 ABCDEFHIJ 9完 ペナルティ+1452
 3位 【若葉】 ABCDEFGIJ 9完 ペナルティ+1614


「って、はあ!? なんでカズミの野郎が2位に居んのよ!?」

 あいつ、あの後で、Hを通して、その上Cまで修正したわけ!?
 Cは元のコードがあるし、Hもある程度までは組めてただろうとはいえ、たった15分しか時間残ってなかったのよ!? どんだけ超人なのよ!?

 つーか、あたしら、9完のままだったら負けてたじゃん!
 カズミの野郎、さも負けを認めたような台詞を吐いておいて、内心では抜き返す気満々だったんじゃねーか! 相っ変わらずねじ曲がった性格してやがんなぁ!?

 はぁ……。これは、若葉の3人に、感謝しないとね……。
 あそこで発破をかけてもらえてなかったら、確実にカズミに負けてた……。

「あ、そうそう。他のチームのみんなから、サクヤちゃんへの伝言を預かってるんだよ〜。えっとね、たしかカズミちゃんは……」

 ――はは。私に勝ったと勘違いしてぺらぺらと余計なことを喋りまくっていた秋葉サクヤの天高く伸びる鼻っ柱をぽっきり折ってやったら、どんな表情が見られるのか楽しみにしてたんだけどね。残念だよ。今度こそ約束通り、君達の“チーム名”を返してもらえるよう、スタッフに取り計らっておいた。それでは、またどこかで会おう。

「ああもう本当に性格最っ悪だなあいつは!」
「で、でもね、サクヤちゃん。カズミちゃんが、わたしたちの“名前”を奪ったのって、きっと、わたしたちにもっともっと強くなって欲しかったからじゃないかなー、なんて。……あ、こ、これは、ただのわたしの想像なんだけどね!」
「……分かってるわよ、そんなこと」
「え?」
「あいつの思惑くらい、お見通しだっての。緋笠カズミが心の底から望んでいるものは、強者との胸躍る闘い、それだけよ。その感情は、多かれ少なかれ、全ての競技プログラマーが持っているものだとは思うけど、それを極端に純化した存在が、あいつ。その気持ちだけは、認めてやってもいいわ」
 もっとも、認めていいのは本当にそこだけで、あいつとあたしは、たとえ天地が引っくり返ったとしても決して相容れることはないだろうがな!
「おぉ〜、さすがサクヤちゃん。……それから、ブレインネクサスの2人からは」

 ――バーカバーカ! 10完とか頭悪いんじゃないの?
 ――馬に蹴られて死んじゃえバーカ!

「子供か!!」
 いや、子供だけどさ!!
 なんか途中からカズミにもろ潰されてたのは認識してたけど……。まあ、来年がんばれ。
「次は、絵空トオルちゃんからだね」

 ――ところで、“世界一(せかいいち)”っていうのは、りんごの品種の名前なのよぉ。知ってた? 他にも“黄王(きおう)”なんて名前のりんごもあるから、今度(イエロー)コーダーになってみるのもいいかもしれないわねぇ。

「知 る か ! !」
 そしてなぜそれをわざわざ別室で寝ているあたしに伝えようとする!!
「えっと、最後は、若葉のカエちゃんからだよ〜」

 ――サクヤ先輩。ごめんなさい。先輩の言う通り、私たちは、思いあがっていたのでしょう。先輩の汚いところを目の当たりにして、自分たちの未熟さを思い知らされました。

「お、ようやくまともそうなメッセージが来たわね……」

 ――Hを通すため、涙と鼻水で顔をぐしゃぐしゃにして机にへばりつきながら、鬼気迫る表情で二本の腕を奇怪な軌道で振り回し、白目を剥いて首をがくがくと揺らしながら闘うその姿は、率直に言って正視に耐えないものでした。

「え、ちょ、何。<領域拡張(フライオーバー)>中、あたしそんなことになってんの? ねえタマキ。どうなのよ」
「………………」
「黙って目を逸らされたーーーーっ!」
「サクヤちゃん。……世の中には、知らない方が幸せなことって、あると思うよ?」
「いやーーっ! その優しさが痛い! そして怖い!」

 ――それでも、私たちは目を背けませんでした。サクヤ先輩が見せてくれると言った“汚いもの”を、一つ残らず瞳に焼き付けようと、病的に蠢く名状しがたき異形の物体から、決して目を逸らしませんでした。

「やめて! むしろ逸らして! 汚いものって、そういうクトゥルフ的なことじゃないから! もっとこう、比喩的な何かだから!」

 ――それで、私たちは悟りました。私たちの決意なんて、あんなの、覚悟の内にも入らなかったんだ、って。女であることを冒涜するような真似をしてまで1つの問題にしがみ付く、Acceptedに懸けるサクヤ先輩の悲壮な決意が余すことなく伝わってきて、正直、泣きそうになりました。

「泣かないで! お願いだから目を閉じて! あたしもまだ女を捨てたくないーーーっ!」

 ――私たちでは、まだまだサクヤ先輩の境地に至ることはできない。そう痛感させられました。そんな私たちが、先輩に対して、余計なお世話でしかない出過ぎた配慮をしてしまったことを、お許しください。今度こそ、正しい意味で言います。サクヤ先輩、申し訳ありませんでした。

「や、まあ、一番言いたかったことは伝わってるみたいだけどさ……」

 ――P.S. あの後【若葉】の3人で話しあったのですが、やっぱり先輩のあれを真似するのだけはちょっと…………。なので、私たちは私たちなりの道を進んでみることにします。それでは、また。

「……ねえタマキ。今日の大会で、あたしのことを慕ってくれる貴重な後輩が3人失われたような気がしてならないんだけど」
「……気のせいだと思うよっ♪」
 思いっきり目を逸らされた。


 ◆


「ふう。厳しい闘いだった」
 追加された料理を食べつくして戻ってきたらしいトウコと合流したのが、それからさらに20分後。
 もちろん、トウコが持ち帰ってきたタッパーの中身については、予想通りに天丼なやり取りが行われた。

「トウコちゃん、凄かったんだよぉ。人がぎゅうぎゅうに詰まったパーティー会場の中で、まるで水の中をすいすい泳ぐみたいに動いて、目にも止まらぬ速さで次から次へと自分の皿に料理を取っていくの。それを見ていた人たちからは、“無重力の妖精(ダンシング・フェアリー)”なんて呼ばれてたんだよっ! 凄いよねぇ〜」
「や、それ別に凄くないから。馬鹿にされてるだけだから」
 ちなみに、あたしの攻撃を軽々かわせるほどのトウコの体さばきは、こうしたパーティの場で、できる限り多くの料理を確保するために鍛え上げられた技術らしい。本人から聞いた。奴いわく、「立食パーティーは、戦場だ」とのこと。
「サクヤに同意。あの鮮やかさはあくまで副次的に磨き上げた技術の賜物。私の本領はあくまで力強さにある。ゆえに“貪欲戦車(グスタフ・マックス)”の方が的を射ていて好み」
「や。それも馬鹿にされてるだけだから。自己分析とかいらないから」
 そもそも、あんたのそれ、能力(スキル)の名前でも何でもないからな?

「あ、そうだサクヤちゃん。チーム名が【__________(ノーネーム)】のままじゃ世界大会への登録ができないから、早急に名前を決めてくれ、って、ジャッジの人から言われたよ?」
「ああ、そういえばそんな話もあったわね……」
 あたしたちが、チーム名なし、なんてふざけた状態でICPCに参加していられるのは、カズミが赤白(ターゲット)コーダーの権限を悪用して日本のジャッジに要求をねじ込んだからだ。
 日本国内で行われるアジア地区予選まではそれで良かったが、世界大会に出るとなれば、さすがに名無し(ノーネーム)のままというわけにもいかない。
「おぉ〜。やっとノーネームじゃなくなって、元の名前に戻れるんだねぇ〜」
 タマキの言うことはもっともだ。
 カズミから “チーム名”を返還された以上、すぐにでも昔の名前で再登録するのが自然な行為だろう。
 でも、あたしには少し、思うところがあった。

「ねえ、聞いてくれる? あたしにちょっと考えがあるんだけど」
 タマキとトウコに向かって、言う。
「昔の名前に戻すのもいいけどさ、あたし実は、この【__________(ノーネーム)】って名前も、結構気に入ってんのよね」
 いくらカズミによって無理やり押し付けられた、チーム名とも言えないような、名前の搾りかすだったとしても。
 1年間ずっと付き合い続けていれば、それなりに愛着も湧く。
「それにさ。【__________】って、あたしたちが初めて世界大会に進出した記念すべきチーム名……っていうのも変だけど、まあ、呼び名なわけじゃない。だったら、縁起もいいし、いっそのことこのまま突き進んでみない? って提案なんだけど……どう?」
 冷静に考えてみれば、無茶苦茶なことを言っている気が、しなくもない。
 単に、カズミに対して皮肉が言いたいだけだと受け取られてもおかしくない。
 しかし、あたしのこの提案は、意外なことに2人にも好評だった。
「いいねぇサクヤちゃん! それで行ってみようよ!」
「タマキに同意」

 とはいえ、本当に“名無し”のままでは、世界大会への登録ができない。
 そこで、ちょっとだけ屁理屈をこねる。
「そもそも、今のあたしたちのチーム名が【__________】になってるのって、ジャッジ側の処理の都合なのよね」
 名前がないのだから、本来ならばあたしたちのチーム名は、空文字列で【】とでもなっていなければならない。
 でも、それだと多くのチーム名を機械的に処理するときに、色々な問題が生じる。そこで便宜的に、空白のように見える文字列をチーム名として定義しておこうという事情があって、あたしたちのチーム名は【__________】になっているのだ。
 これをそのまま、正式なチーム名として登録してしまおう、というわけだ。
「そっかぁ〜。でも、読みは? これも“ノーネーム”のまま?」
 確かに、そういう手もある。
 空文字列では名前を呼ぶときに不便だからと、便宜的につけられた呼び名が“ノーネーム”なのだから、同様にこれを正式なチームの呼び名として登録してしまえばいいのだ。
 でも、ちょっとそれでは味気ない。
 なので、最後にちょっぴり捻る。

「あたしの能力(スキル)、<領域拡張(フライオーバー)>。タマキの能力(スキル)、<固定賽子(バウンドレス・ダイス)>、トウコの……二つ名? “貪欲戦車(グスタフ・マックス)”。Over(超過)Boundless(無限)Max(最大)。よくもまあ、こんなに上昇志向なネーミングが集まったもんだと思うわ。けど、あたしたちは今日の闘いで、足元がお留守になっていたせいで、相当な苦戦を強いられた」
 【若葉】の急浮上に巻き込まれて溺れかけ、カズミの巻き返しにも気づきすらしなかった。
「だから、もう一度足元をしっかり見直そうっていう、戒めのつもりで、ね。たとえどんなに実績のある強豪チームだって、コンテストが始まった直後のスタートラインはみんな0完。最低の(アンダー)スコアから始めて、しっかり地に足をつけて、最大限の勢いでどこまでも飛躍していこう、って願いを込めて。いつだって、あたしたちを支える土台になってくれる、うちのチームの名前は――――」



 そしてあたしは、頭に思い描いたチーム名を、口にした。



 (了)







 (※) この記事は、@highjelliesによって、Competitive Programming Advent Calendarの25日目用に書かれたものです。

 (※) 我々@highjellies, @iwiwi, @omeometoの3人は、今年の11月に、チーム【__________】としてICPC2011アジア地区予選に参加し、優勝してきました。その記念に参戦記を書こうと思ったのですが、ここで、「@iwiwiの目には、今回のICPCはどのように映っていたのだろう?」という疑問が生じました。

 (※) UTPC2011の問題文によると、どうやら@iwiwiには、周りの競技プログラマーがみな美少女に見えているらしいのです。そこで、「@iwiwiの主観フィルターを通して見たICPCとは、このようなものなのではないか」という想像をもとに描かれた参戦記が、この記事です。このような理由のため、客観的事実とは異なる描写が一部含まれていますが、ご了承ください。

 (※) 本記事中に登場したC問題とG問題のコーナーケースは、実際に【__________】が本番中にAcceptedしたコードを撃墜することができます。