プログラミング備忘録

プログラミングに関することをつらつらと。

AtCoder Beginner Contest 043

成績

  • 700点、77分29秒=125位

B問題で思わぬ落とし穴にハマって2回ペナルティ食らったのがよくなかったが、D問題の部分点解法まで解けたのでわりと満足。翌日は朝早くから予定があったので解答時間途中で終了。

解法メモ

A問題

与えられたNに対して、必要なキャンディーの個数は\sum_{n=1}^N n = N(N+1)/2である。

B問題

入力文字列sに対して、エディタ上の文字列K*1を用意する。
|s|\leq 10だから、|K|\leq 10とわかる。ヌル文字を含めて11文字確保されていれば十分。
sの文字を先頭から順に見ていき、

  • 次の文字が0のときは、Kの末尾に0をつける。
  • 次の文字が1のときは、Kの末尾に1をつける。
  • 次の文字がBのときは、Kが空なら何もしない。Kが空でない時は、末尾から1文字消す。

最初にKをヌル文字で埋めておき、Kの現在の文字位置を示す変数jを用意すればよい。Kの先頭がヌル文字ならばKは空だから何もしない。そうでない時はKj文字目をヌル文字に置き換えて、jをデクリメントする。

C問題

N個の整数すべてを最小コストで書き換えられる整数をKとおく。コストの総和は
(a_1-K)^2+(a_2-K)^2+\cdots+(a_N-K)^2 \\ = NK^2-2(a_1+a_2+\cdots+a_N)K+a_1^2+a_2^2+\cdots+a_N^2 \\ = N(K-(a_1+a_2+\cdots+a_N)/N)^2-(a_1+a_2+\cdots+a_N)^2/N+a_1^2+a_2^2+\cdots+a_N^2
だから、K=(a_1+a_2+\cdots+a_N)/Nとわかる。

実際には、(a_1+a_2+\cdots+a_N)/Nは整数とは限らないので、一旦Kをdouble型で計算し、nearbyint関数などで最近接整数[K]をとるとよい。
そのときのコストは-(a_1+a_2+\cdots+a_N)^2+a_1^2+a_2^2+\cdots+a_N^2をバカ正直に展開するよりは最初から(a_1-[K])^2+(a_2-[K])^2+\cdots+(a_N-[K])^2を計算するほうが早い。

N個の整数の範囲が-100\leq a_i \leq 100だから全探索でもすぐに終わるが、こういう問題を数学的に解けるようになっておいたほうがあとで生きてくることがあると思う。

D問題

部分点解法

1\leq a < b \leq |t|なるa,bに対して、a文字目からb文字目までの間に各アルファベットが何回出てくるか毎回数え、どれかひとつでも過半数になった瞬間に探索を打ち切って答え(a b)を表示する。2\leq |s|\leq 100を満たすデータセットに対しては時間内に答えが出せる。

満点解法

tがアンバランスな文字列であるのは、tの部分列としてXXまたはXYXの形(X,Yは異なる任意のアルファベット)が存在する場合に限る*2
各アルファベットXに対して、t内で、ある場所の1文字先または2文字先がXになっているところを探索する。あればそこで探索を打ち切ってa bを表示、なければ-1 -1を表示。

*1:何を思ったのかキーボードのKにしていた。

*2:証明は文字数に対する帰納法を用いるのが簡単?