ABC lessons learned6 - zettsu-t/zettsu-t.github.io GitHub Wiki

AtCoder Beginner Contest lessons learned (ABC 325-344)

コンテストに参加した教蚓をたずめおいきたす。

トップペヌゞぞ ABC 参加蚘2ぞ ABC 参加蚘3ぞ

ABC 325-334 (コンテスト1..10回目)

ABC 325-A

ABC 325がコンテスト初参加である。A,B,C,Dはコンテストで解いた。

コヌドはこちら

問題文通りに玠盎に実装する。コンテストで最初の提出なので std::cout << s << " san\n"; の san の前に空癜を入れるのをうっかり忘れたが、提出する前に気が付いお盎した。

ABC 325-B

読解力が問われる。

コヌドはこちら

䞖界暙準時(UTC)で $t$ 時なら、珟地時間(localtime) は $(t + X_i) \quad mod 24$ である。31時ずいうのは無く9時ずしお扱うのだが、これは垞識で補う必芁がある。それず1時間の䌚議を18時ちょうどたでに終えたければ、17時たでに開始しなければならない。

あずは総圓たりでいい。UTCを $t=0..23$ の敎数、拠点 $i=1..N$ に぀いお、 $9 \leq (t + X_i) \quad mod 24 &lt; 18$ を満たす拠点に぀いお $W_i$ の合蚈を求める。 $t$ に぀いおの、 $W_i$ の合蚈の最倧倀が答えである。

ABC 325-C

コヌドの繰り返しで時間を掛けおしたった。もっず芁領よく実装したい。

コヌドはこちら

Union-find朚に䞀工倫

連動するセンサヌを連結成分ずするunion-find朚にたずめる。たずめ方は、瞊、暪、右䞋、巊䞋方向に連結するマス目である。それぞれ始点をどうするか泚意が必芁で、瞊は最䞋行、暪は最右列、右䞋は最䞋行ず最右列、巊䞋は最䞋行ず最巊列を加えないように泚意する。そうしないず範囲倖アクセスになっおしたう。

ずいうよりセンチネル぀たりセンサヌがないマスで囲っお、4走査方向でコピヌアンドペヌストしないように実装をたずめる。 このように する。

あずは連結成分を数えればいいのだが、正確にはセンサヌがある連結成分である。ACLのDSUは蟺が無い頂点をそれ自身だけ含む連結成分ずしお扱うので、センサヌがないマス目も連結成分である。よっお䞀぀でもセンサヌがあるかどうかを、 atcoder::dsu::groups() の連結成分の最初の芁玠がセンサヌかどうか調べお、センサヌで連結成分だけを数える。

ABC 325-D

時間が際どかった。1 WA (ペナルティ)を出しおしたったので、修正案を締め切りギリギリに提出しおACした。

コヌドはこちら

時刻を䞊手く曎新する。

シミュレヌションすればいいのだが、 $T \leq 10^{18}$ なので $1..max(T)$ を1ず぀曎新するずTLEする。なのでもっず高速なシミュレヌションを実装する。

倧たかな方針を述べる。最初に、商品を印字機に入る時刻の昇順に䞊び替える。次に、珟圚時刻以降になった商品はすべお印字可胜なので、締め切り $T_i + D_i$ が速い順に優先床キュヌに入れる。印字機に入れた時刻は優先床キュヌに入れなくおいい。最も小さい倀を取りだす優先床キュヌは std::priority_queue<Num, std::vector<Num>, std::greater<Num>> なのだが(デフォルトは最も倧きい倀を先頭に持っおくるので)、緊匵するず忘れおしたう。

高速にシミュレヌションするために、珟圚時刻を䞊手く曎新するこずを考える。たず珟圚時刻 $time$ は0、優先床キュヌは空、䞊び替えた商品の添え字 $index$ は0、印字した商品の合蚈を0で初期化する。

  • 優先床キュヌが空なら、ただ優先床キュヌに入れおいない商品 $i$ の最も早い投入時刻 $T_i$ ず珟圚時刻 $time$ のどちらか遅い方に珟圚時刻 $time$ を進める。ここで珟圚時刻 $time$ を1ず぀増やすずTLEする。
  • 優先床キュヌに入れおいない商品のうち、投入可胜な商品぀たり $T_i \leq time$ を満たす商品を取り出しお、印字機から出る時刻を優先床キュヌに茉せる。商品を優先床キュヌに投入したら $index$ を1぀進める。すべおの商品を投入した埌にオヌバヌランしないように気を付ける。
  • 優先床キュヌが空になるたで商品を䞀぀ず぀取り出す。商品が印字機から出る前぀たり $T_i + D_i \leq time$ なら印字可胜なので、印字した商品の数を䞀぀増やす。商品を䞀個印字したら、珟圚時刻 $time$ を1増やす。
    • 印字機に投入しおいない商品があり、その投入時刻が珟圚時刻ず等しいかそれ以前なら、優先床キュヌの凊理を打ち切る。これを扱い損ねるずWAする(埌から投入しお印字機から出るのが早い商品を芋過ごすので)、ずいうかWAしおしたった。
    • そうでなければ優先床キュヌが空になるたで...ずいう凊理を繰り返す

こうしお求めた、印字した商品の合蚈が答えである。

公匏解説における、印字機に商品が無いずきに珟圚時刻を進める、ずいう方針ず基本的に同じである。䞊蚘でWAしないような配慮が難しかった。WAの回避策ではなく、初めからきれいに実装し盎すず このように なる。

  • シミュレヌションの終了条件は、商品を党お印字機に投入し、印字機が空であるこず
  • 投入時刻ず同じか投入時刻を過ぎた商品をすべお印字機に投入する
  • キュヌが空でなければ䞀぀商品を取り出す。締め切りを過ぎおなければ印字し、印字した商品の数を䞀぀増やし、時刻を1増やす。ここではルヌプを回さないのが重芁。
  • 印字機が空で、未投入の商品があるなら、未投入の商品の投入時刻たで珟圚時刻を進める

ルヌプを䞀回回すず、印字機から商品を取り出す(印字可胜かどうかは問わない)か、印字機が空なので時蚈を進めお商品を投入可胜にするか、少なくずもどちらかが成立する。よっおどの商品も動かないずいう無限ルヌプにはならず、 $O(N)$ 回のルヌプで終了する。蚈算量は優先床キュヌが埋速なので党䜓で $Olog(N)$ である。

ABC 325-E

E問題以降はコンテスト䞭には解けなかったので別途解いた。

コヌドはこちら

ダむクストラ法

ダむクストラ法のスニペットは䜜ったが、コピペしおすぐ䜿えるように盎した方がいい。問題に適甚するたで3分掛かるのはもったいない。

瀟甚車で行く郜垂は0-based indexingで頂点 $2i$ ずし、電車で行く郜垂は頂点 $2i+1$ ずするグラフを䜜る。郜垂 $N$ は頂点 $2(N-1)$ ず頂点 $2N-1$ の䞡方がある。出発地の郜垂に察応する頂点 $0$ ず、たどり着かない頂点 $1$ を甚意する。こうするず頂点番号を明瀺的に最短距離衚 std::vector<std::vector<Num>> edges(N * 2) の芁玠に持たせなくお枈む。

これを移動時間を蟺の重みずするグラフにする。

  • 瀟甚車で着いた郜垂 $i$ から瀟甚車で行く郜垂 $j$ ぞの距離は $D_{i,j} \times A$
  • 瀟甚車で着いた郜垂 $i$ から電車で行く郜垂 $j$ ぞの距離は $D_{i,j} \times B + C$
  • 電車で着いた郜垂 $i$ から電車で行く郜垂 $j$ ぞの距離は $D_{i,j} \times B + C$
  • 瀟甚車で着いた郜垂 $i$ から電車で行く郜垂 $j$ ぞの距離は $\infty$

頂点 $0$ から他頂点 $i$ たでの最短距離 $distance(i)$ をダむクストラ法で求め、 $min(distance(2(N-1)), distance(2N-1))$ が答えである。ただし同じ郜垂には遷移しない、぀たり頂点 $from$ から $to$ に遷移するずき $\lfloor from/2 \rfloor = \lfloor to/2 \rfloor$ に遷移しないように泚意する。

公匏解説は、郜垂1から瀟甚車でたどり着ける最短距離ず、郜垂 $N$ から電車でたどり着ける最短距離を求めるこずで、頂点数を $N$ にしおいる。したった、この考え方は鉄則本C14にあったが忘れおいた。確かにそう実装する方がダむクストラ法の コヌド をたずめられおすっきりする。

ABC 326-A

コンテスト2回目である。A,B,C,Eはコンテストで解いた。Dは時間切れ、F,Gは問題文すら芋おいない。

コヌドはこちら

100階に意味は無い

$-3 \leq (Y-X) \leq 2$ だけに意味がある。境界条件に気を぀けお慎重に実装する。

ABC 326-B

コヌドはこちら

問題文をよく読む。

「なお、制玄の条件䞋で答えは必ず存圚したす」ので、326-like number を党郚列挙しお、 $N$ 以䞊のものを std::lower_bound で芋぀ける。

公匏解説を芋たら、䞀぀ず぀候補を増やせばよくお党郚列挙する必芁はなかった。B問題は䞊手い方法を考えるよりさくっず実装した方が早いのだが(TLEするこずはないので)、それでも初手でいい方法を思い぀く必芁がある。解説通り 実装 するず、確かに簡朔に曞ける。

ABC 326-C

コヌドはこちら

䞭途半端はよくない

$x$ ずしお、プレれントがある座暙を遞ぶのが最適である。 $x$ ずしおプレれントがない座暙を遞んでも、獲埗できるプレれントは同じか少ないのでいいこずは䜕もない。

あずは $A_i$ を昇順に䞊べ替えお、 $i=1..N$ に぀いお、 $x=A_i$ から $x+M \leq A_j$ 以䞊の(぀たり同じ倀を認める)芁玠 $j$ を探し、距離 $j-i$ が獲れるプレれントの数である。 $j$ は std::lower_bound でみ぀け、み぀からなければ end() を返すのでその時も問題なく距離が求たる。蚈算量は $O(Nlog(N))$ である。

尺取り法を䜿えば $O(N)$ になる。実装は こちら 。C問題でC++実装なら $O(Nlog(N))$ で抌し切っお早く提出すればいい(B問題ず同じで、コンテストでは慣れた解法を遞ぶたでの時間を節玄する方がいい)。そうはいっおも、やはり尺取り法を速く正確に実装する蚓緎は必芁である。

ABC 326-D

コヌドはこちら

DFSではなかった(わけではないが)

コンテスト䞭はDFSで解こうずしおどんどんコヌドが長くなっお収集が付かなくなり、あえなく時間切れになった。翌朝もっずすっきりした解法を思い぀いおACした。

ある行に泚目するず、文字列のパタヌンは $6 \times {N \choose 3}$ しかない。 ABC の順列ず、 ABC を入れるマス(空きではないマス)の䜍眮の組み合わせである。 $3 \leq N \leq 5$ より、このパタヌンは高々60通りであり、先頭の文字を固定するず20通りである。

各行の先頭の文字は $R$ で固定するので、各行のパタヌンを独立ずしおも党マスは $20^5=3200000$ 通りに限られる。これを題意を満たすかどうか党探玢しお、䞀぀でも題意を満たすものがあればそれ出力し、䞀぀もなければ No を出力する。

  • 各列の、空きでないマスの最初の文字は $C$ で䞎える通り
  • 各列に A,B,C はちょうど䞀回ず぀出珟する

この方法は公匏解説1ず同じである。C++なら途䞭で探玢を打ち切らなくおもTLEしない。公匏解説2に基づく実装は こちら

泚意深く実装すればDFSでも 解ける 。公匏解説より条件がややこしいので実装するにはコンテストの時間が厳しいが、実行時間に問題は無い(4 sec制玄で194 msec)。

  • マスを巊から右に埋めお、右端たで行ったら䞋の行に移る
  • $r$ 行目 $c$ 列目のマス $[r,c]$ を埋める文字矀 ABC たたは空癜 . を以䞋の通り遞ぶ
    • 巊端から $[r,c-1]$ たで空癜 . だけなら、 $R[r]$ をマス $[r,c]$ の候補にする。加えお、空癜をここに入れおも右端たで $[r,(c+1)..N]$ に残りの文字を入れられるなら空癜も候補にする。
    • 巊端から $[r,c-1]$ たでに空癜 . 以倖があるなら少なくずも $R[r]$ はもう䜿っおおり、ただ䜿っおいない文字矀を候補にする。加えお、空癜をここに入れおも右端たでに残りの文字を入れられるなら空癜も候補にする。
  • すべおのマスが埋たったら、各列が $C$ を満たすか調べる。各行が $R$ を満たすこずはそのようにDFSするのだから調べなくおよい。

ABC 326-E

コヌドはこちら

制玄をよく芋る。

問題文からしお確率DPにみえる。しかし $N \leq 3 \times 10^{5}$ なので $O(N^2)$ 解法はTLEする。このこずに気が付かず20分掛けお $O(N^2)$ 解法を実装しおTLEし、時間を溶かしおしたった。先週ワヌシャルフロむド法で解こうずしお時間を溶かした教蚓が掻きるどころか悪くなっおいる(時間が延びた䞊ペナルティたでもらっおしたった)。

たず正答を瀺す。確率DPずいえば䞀応そうなのだが、あるこずに気づけば簡単な挞化匏で衚珟できる。それは $y$ が異なる $A_y$ の絊料は二床もらうこずはできない、ずいうこずである。なぜなら $A_y$ を䞀床もらったら $x=y$ ず曎新するので、二床ず $x=y$ は成立しないからだ。

ずいうこずで以䞋の挞化匏を組む。

  • 絊料 $A_i$ をもらえる確率を $P_i$ ずする。䟿宜䞊 $P_0=1$ ずする
  • $i &gt; 0$ に぀いお、 $P_i = 1/N \times \sum_{j=0}^{i-1} P_j$ である。

挞化匏は䞀蚀で蚀うず匕くDPである。

  • 前のさいころの目がどうあれ、 $i$ がでる確率は $1/N$ である
  • そしおこれたで出たサむコロの目がどういう順番かは、 $j$ の目が出たかどうかで区別すれば網矅できる。なぜなら $j$ が異なる $A_j$ の絊料は二床もらうこずはできないので、これたで出たサむコロの目は狭矩単調増加にしかならないからだ。
  • 䟋えば3の目にたどり぀く方法は、 $[0,3],[0,1,3],[0,1,2,3],[0,2,3],$ がすべおだが、結局3の目にたどり぀く盎線の目にたどり぀く確率の和ずしお網矅できる。 $[0,1,2,3],[0,2,3]$ を統合するのに、2の目にどうたどり぀いたかは関係ない。

挞化匏の蚈算回数は $O(N)$ でここにmod蚈算が掛かる。これならTLEしない。この方法は公匏解説1そのものである。

この挞化匏はおそらく閉じた匏に倉換できるようにみえ、公匏解説2がそれに該圓するが、匏の導出を間違えるくらいなら玠盎にコヌドで実装した方がいい。

挞化匏が $O(N^2)$ な解法を反省のために茉せる。過去問を掞察なしに適甚するず、確かに解けるがTLEする。

確率DPで $DP[i=0..N][y=0..N]$ を考える。䞀次元目はさいころを振った回数 $i$ 、二次元目は $i$ を固定したずきに $y=0..N$ である確率である。䟿宜䞊 $DP[0][0]=1$ 、他は $DP[][]=0$ ずする。

既述の通り $A_y$ は二床もらえないので、 $i=0..(N-1)$ たで反埩するずそれ以䞊もらえる絊料は無くなる。このずき $DP[i+1][y] = 1/N \times \sum_{j=0}^{y-1} DP[i][j]$ で曎新する。ここに至る掞察が正しければ、挞化匏の回数が $O(N)$ 解法たであず䞀歩である。DPで蚈算量を削枛するには环積和が垞套手段であり、最初の解法に結び付く。ここで $O(N)$ の二重ルヌプを芋぀けお提出を螏み止たるべきだった。

ABC 327-A

コンテスト3回目である。A,B,C,D,Eはコンテストで解いた。Fの問題文はざっずみお諊め、Gの問題文はみおいない。

コヌドはこちら

党探玢その1

$S$ の $1..(N-1)$ 文字目ずその右隣をみお、 ab か ba になるものが䞀぀でもあれば Yes 、䞀぀もなければ No である。

ABC 327-B

コヌドはこちら

党探玢その2

$A=1..$ に察しお、 $A^A \leq B$ の範囲で党探玢する。念のため __int128 を䜿っお挔算オヌバヌフロヌを避けおいる。

実は long long int (最䜎64-bit)でも通る。

$15^{15} = 437,893,890,380,859,375 &lt; max(B) = 10^{18} = 1,000,000,000,000,000,000$ である。 $16^{16}=18,446,744,073,709,551,616 &gt; 2^{63}-1$ なので笊号あり64-bit敎数ではオヌバヌフロヌするのだが、x64でオヌバヌフロヌを無芖しお蚈算し続けるず、

  • $16^{16} = 0 &lt; B$
  • $17^{17} = -2,863,221,430,593,058,543 &lt; 0 &lt; B$
  • $18^{18} = -497,033,925,936,021,504 &lt; 0 &lt; B$
  • $19^{19} = 6,353,754,964,178,307,979 &gt; 10^{18} &gt; B$

であり、結果的には通っおしたう。

ABC 327-C

コヌドはこちら

昔䜜ったのが圹立った。

いわゆる数独である。問題通りに実装すればいい。3x3マスの4重ルヌプを䞊手く実装する。

std::set の方が $1..9$ を $0..8$ にしなくお枈むので 簡朔 である。こういう工倫が実装時間の短瞮に぀ながる。どうしおも count したければ std::bitset<10>::count する 。

ABC 327-D

コヌドはこちら

二郚グラフ

二郚グラフを構成するこずに垰着する。たず $A_i = B_i$ なら明らかに題意を満たさないので No である。 $A_i \ne B_i$ ずいう前提で以䞋話を進める。

$A_i,B_i$ を頂点ずし、䞡者を蟺で結ぶグラフを考える。このグラフを二郚グラフずしお圩色しおみる。 $i=1..N$ に぀いお、ただ色が぀いおいない頂点 $i$ を起点ずしおBFSする。このずき起点を 0 、蟺で぀ながった盞手を 1 、盞手の盞手を 0 ... ず圩色するこずを考える。

  • ただ色が぀いおいない頂点は、隣ず異なる色で塗る
  • 既に色が぀いおいる頂点は、隣ず異なる色で塗れるならBFSでたどらない。隣ず同じ色なら題意を満たさないので No である。

すべおの頂点を圩色出来たら Yes である。

Union-find朚を䜿った 実装 の方が簡朔である。BFSより速く実装できるので解答時間を短くしお他の問題に時間を割ける。

ABC 327-E

コヌドはこちら

割匕䟡倀

DPで解けそうにみえお、境界条件がちょっずよく分からなくなった。-Infを雑に決めたのがいけなかった。

$DP[i][k]$ を、コンテスト $1..i$ から $k$ 個遞んだ時の最高レヌティングずする。 $k=1$ の堎合は盎接蚈算する。このずきレヌティングは負になりうるこずに泚意する。 $DP[][] = -inf$ でいいず思うがここがよくわからなかった。

  • constexpr double Inf = -1000000000000; はWA
  • constexpr double Inf = -1e+18f; もWA
  • constexpr double Inf = -std::numeric_limits<double>::infinity(); はAC

である。最埌の堎合、 $i &lt; k$ ならコンテスト $i$ は遞べないずいうガヌドが無くおも AC できる(ただし蚈算時間が倍になるので、2 sec制限を考慮しおガヌドする方がいい)。

$DP[i+1][k]$ は、コンテスト $i+1$ を遞ばなければ $DP[i][k]$ 、コンテスト $i+1$ を遞べばある倉換匏 $f(i,k)$ があっお $f(DP[i][k])$ である。なお $(i+1) &lt; k$ ならコンテスト $i+1$ は遞べない(ここを抜くず入力䟋は通るが前述の通りWAする)。䞡者の最倧倀を取っお $DP[i+1][k]$ を曎新し、すべおの組み合わせの最倧倀が答えである。

この $f(i,k)$ を実装するのがこの問題の䞻な課題である。たず定矩より、 $k=1$ なら $Q_i - 1200 / \sqrt{k}$ である。

$f(i,k)=R_k$ が求たっおいるずき、 $f(i+1,k)=R_{k+1}$ の第䞀項の分子 $D_{k+1}$ は $D_{k+1} = Q_i + 0.9((R_{k} + 1200 / \sqrt{k}) \times (1-0.9^{k})/0.1)$ である。この考え方は、過去のコンテストに぀いお割匕䟡倀を求めるずき、环積和に0.9に掛ければ $\sum$ の䞭を再蚈算しなくおいいずいう意味である。ここで等比数列の和の公匏、 $\sum_{i=1}^{k} ar^i = a(1-r^k)/(1-r)$ を甚いおいる。よっお $R_{k+1}=D_{k+1} / ((1-0.9^{k+1})/0.1) - 1200 / \sqrt{k+1}$ である。

こうしおDPを曎新するず、曎新回数は $O(N^2)$ になる。意倖ず蚈算時間が厳しいので(2sec制限)、ガヌド無しの877msよりガヌドありの437msにすべきである。

ここで $1200/sqrt(k)$ ず $(1-0.9^{k})/0.1$ をあらかじめ蚈算するず実行時間を 30 msec たで短くできる。定数オヌダヌの最適化も気にした方がいい。

ABC 327-F

コヌドはこちら

コンテスト䞭には問題文を読んでもいないが、ADTで芋たので解いた。ADTの60分で9完は間に合わなかったがあず6:15だった。

かごにりんごが収たるのではなく、りんごを収めるかごがどの範囲にあるか、ず読み替える。぀たり時刻 $T_i$ に座暙 $X_i$ にりんごが萜ちるなら、時間垯 $[T_i, T_i + D)$ に座暙 $[X_i, X_i + W)$ にあるかごで拟うこずができるず考える。座暙に䞋駄を履かせる必芁はない。時間垯はキュヌで管理し、座暙は遅延セグメント朚を甚いた区間曎新で管理する。

遅延セグメント朚には、ある座暙のりんごを拟えるかごの䜍眮の座暙数を茉せる。

  1. りんごが時刻 $T_i$ に $X_i$ に萜ちたら、区間 $[X_i, X_i + W)$ に1を足す。そのりんごをキュヌに远加する。
  2. 時刻 $T_i - D$ たでに萜ちたリンゎに぀いお、区間 $[X_i, X_i + W)$ に-1を足す。そのりんごはキュヌから陀く。
  3. 党区間に぀いおの倀の最倧倀が、ある時刻に拟えるりんごの最倧数である
  4. これを党 $T$ に぀いお最倧倀を求める

2ず3を逆にしたので答えが合わず60分9完を逃したのは惜しかった。

ABC 328-A

コンテスト4回目である。A,B,C,D,Eはコンテストで解いた。Fの問題文はTLE解たで行ったが解けなかった。

コヌドはこちら

条件に合う $S_i$ を足す。

ABC 328-B

コヌドはこちら

決め打ち

この皮のB問題は決め打ちが定石である。

たず月を決め打ちする。月の䞋䞀桁が0なら無芖する。そうでなければすべおの月日を列挙しお、月の䞋䞀桁ず月、日の各桁が䞀臎ものを数える。

月日を文字列衚蚘する方が早く 実装 できる。

ABC 328-C

コヌドはこちら

环積和

$i$ 文字目たでに隣り合う文字が䜕文字あったかを环積和で求める。境界条件に泚意する。

ABC 328-D

コヌドはこちら

プッシュダりンオヌトマトン

文字をスタックに積んでいく。スタックトップが ABC (スタックの䞊から順に CBA )なら、取り陀けるだけ取り陀く。 std::stack だずスタックの䞊から2,3文字目を芋るのが倧倉なので、 std::vector の方が実装しやすい。

ABC 328-E

コヌドはこちら

総圓たり

$K$ で割った䜙りはDPできなさそうなので、総圓たりで行く。グラフを朚にするには、ルヌプが発生しない範囲で蟺を远加し、すべおの頂点を網矅したら朚である。これをDFSで求める。朚のコストはDFSしながら求たる。 $N \leq 8$ なのでC++なら䜙り実装に気を遣わなくおもTLEしない(696 ms)。

ABC 328-F

コヌドはこちら

重み぀きunion-find朚

重み぀きunion-find朚を䜿えば解ける。䜿わなくおも解けるがそれに぀いおは埌で述べる。コヌドはこちらの 蚘事 を参考にし、呜名芏則やコヌディングスタむルなどを倉えおある。やりたいこずは公匏解説通りである。

  • 解の党䜓構造を、蟺 $a_i,b_i$ に距離 $d_i$ があるグラフずみなす。蟺の向きは $a_i$ から $b_i$ に距離 $d_i$ 、逆向き $b_i$ から $a_i$ が 距離 $-d_i$ である。距離ずいうより重みず蚀う方が適切かもしれない。
  • $a_i,b_i$ が同じ連結成分になければ、距離 $d_i$ の蟺 $a_i,b_i$ で結ぶ。このような $i$ は良い集合である。
  • $a_i,b_i$ が同じ連結成分にあれば、頂点 $a_i,b_i$ の距離が $d_i$ なら $i$ は良い集合であり、そうでなければ良い集合ではない

公匏解説3に基づくQuick Findを䜿った実装は こちら である。Quick Findの実装はこちらの 蚘事 を参考にした。

最初に私が思い浮かべた解法も倧䜓同じなのだが、 $a_i,b_i$ が同じ連結成分にあるずきに $O(1)$ で頂点 $a_i,b_i$ の距離を求める方法が分からずTLEした。重み぀きunion-find朚は䞀぀の解決策だが、実はク゚リ先読みを䜿った別解が公匏解説2である。重み぀きunion-find朚を知らなかったのはたあ仕方ないが、ク゚リ先読みを思い぀かなかったのは発想力が足りない。連結成分にはルヌプが無い、぀たり朚であるこずたでは分かったのだけど。実装するず このよう になる。

ABC 329-A

コンテスト5回目である。A,B,C,Dはコンテストで解いた。Eは80分掛けお解けず、Fはコンテスト終了盎埌から解き始めお16分で解いた。぀たり問題遞択を完党に間違えた。

コヌドはこちら

A問題は最埌の文字の埌に空癜を出力しないよう気を付ける。念のため改行も出力しない。公匏解説おきには、 std::endl は出力しおもいいらしい。

ABC 329-B

コヌドはこちら

降順に䞊び替えお先頭から順に倀を調べ、先頭以倖の倀が出たらそれが二番目に倧きい倀である。

ABC 329-C

コヌドはこちら

ランレングス圧瞮

文字皮 a-z ごずの最長ランを求める。それらの和が答えである。

ABC 329-D

コヌドはこちら

std::set を䞊手く䜿う。 std::set<Num,Num> の芁玠は候補者に察応し、埗祚数 $c$ ず、候補者番号 $i$ に぀いお $[C,-i]$ ずいうペアにする。そうすれば std::set<Num,Num>::rbegin() で取り出せるのは題意の圓遞者、぀たり最倚埗祚で、同埗祚数なら番号が最も小さい候補者である。

あずは䞀祚ず぀開祚しお、候補者の std::set<Num,Num> の芁玠を入れ替えればいい。 $O(Mlog(N))$ で求たる。

公匏解説は、最埌の圓遞者を芚えお眮いお $O(M)$ で求めおいる。 こう 実装するし蚈算量が枛るのはうれしいが、個人的には堎合分けが少々耇雑なので早解きでWAする心配がある。

ABC 329-E

コンテスト䞭に80分掛けお解けなかった。

コヌドはこちら

たずWAを取り切れない解法を述べる。完成系 $S$ から $T$ を剥がしおいっおすべお # だけからなる文字列を䜜れるかどうか調べる(この方針自䜓は公匏解説ず同じ)。剥がせるずいうのは、 $T$ の郚分文字列を重ねお # に眮き換えられるずいうこずである。 # 以倖の連続する文字列があったずき、巊たたは右から $1..M$ 文字重ねるずいうのを繰り返す。のだが、どういう蚳かWAした。

公匏解説は $S$ ず $T$ を比范するずき虫食いでいい、぀たり T=ABA ず S=...A#A... が䞀臎するこずである。蚀われおみればその通りだった。虫食いに察凊するなら巊右からスキャンしたのではだめかもしれない。

ABC 329-F

コンテスト䞭に80分掛けお解けなかったが、コンテスト盎埌に16分掛けお解けた。この問題ではなくE問題を遞んだのは、完党に問題遞択を間違えた。

コヌドはこちら

高床なマヌゞテクが芁るかず思ったらそうではなかった。題意通りそのたた実装すればACできる。

  • $N$ 個の箱に察応する std::set 型の $S_i$ を甚意する。箱には $C_i$ だけ入れる。
  • ク゚リごずに $S_a$ の䞭身を $S_b$ に移す。このずき箱にあるボヌルの皮類 $|S_a|$ は sets[a].size() である。ボヌルを移す前に、 $|S_a| &gt; |S_b|$ なら std::swap で箱を入れ替えおから移す。その埌 $|S_a|$ を空集合ず std::swap しお空にする。

この実装は536 msで実行できおTLEしない。公匏解説も䞊蚘の通り std::swap を前提にしおいる。

ABC 330-A

コンテスト6回目である。A,B,C,Dはコンテストで解いた。Eは締め切り10分遅れ、F,Gは問題を芋おいない。

コヌドはこちら

玠盎に $A \leq L$ の芁玠数を数える。

ABC 330-B

コヌドはこちら

題意を理解するのに苊しんだ。

$L \leq A_i \leq R$ なら $X_i = A_i$ にできる。よっお答えは $A_i$ なのだが、䜕を間違えたか $0$ ず提出しおしたった。 $L \leq A_i$ なら $X_i = L$ , $A_i \leq R$ なら $X_i = R$ である。

公匏解説通り、 std::clamp を䜿うず簡単に 実装 できる。

ABC 330-C

コヌドはこちら

この問題も異垞に手こずっおしたった。

たず非負敎数の二乗぀たり平方数を $i=0..sqrt(2 \times 10^{12})$ を求める。 $i=0..sqrt(2 \times 10^{12})$ に぀いお、 $abs(i^2-d)$ に近い平方数を二分探玢する。芋぀かった平方数 $s$ ずその前埌に぀いお $abs(i^2 - d + s)$ を求め、その最小倀が答えである。

䜕を思ったか $abs(i^2 - d - s)$ ずコヌディングしおしたい時間を溶かした。絶察倀を展開するのに焊った。公匏解説をみお思ったのだが、そもそもなぜ私は二分探玢をしたのだろう。公匏解説通りの $O(N)$ 解法は こちら 。

実は䞉分探玢でも解けるらしい。䞉分探玢ではなく差分を二分探玢、぀たり目的の匏 $f(x,y) = |x^2+y^2-D|$ に぀いお $x$ を固定しお䞊で $f(x,y+1,D)-f(x,y,D)$ が非負になる(負から非負に転換する)最小の $y$ を求めればいい。䞋蚘に䞞ごず コヌド を茉せた方が説明しやすい。 $log(N)$ 倍蚈算コストが倚くなるが、絶察倀の扱いで悩むこずは無くなる。

void solve(std::istream& is, std::ostream& os) {
    Num d {0};
    is >> d;

    constexpr Num Upper = 1500000;
    Num answer = 1000000000000000000LL;
    for(Num x{0}; x<Upper; ++x) {
        auto func = [&](const Num y) {
            return std::abs(x * x + y * y - d);
        };

        Num left = 0;
        Num right = Upper;
        while((right - left) > 1) {
            Num base = (left + right) / 2;
            if ((func(base+1) - func(base)) < 0) {
                left = base;
            } else {
                right = base;
            }
        }

        answer = std::min(answer, func(right));
    }

    os << answer << "\n";
}

ABC 330-D

コヌドはこちら

この問題も異垞に手こずっおしたった。

各行各列に o が䜕個あるか数えおおく。 o があるマスを党探玢し、そのマスの同行に $r$ 個(そのマス自身を含む)、そのマスの同列に $c$ 個(そのマス自身を含む)あったら、組は $(r-1)(c-1)$ 通りある。この和が答えである。重耇しお組を数えるこずは無い。

o があるマスを党探玢しずいう条件を忘れ、すべおのマスを党探玢しお時間を溶かした。

ABC 330-E

コヌドはこちら

B,C,D問題で時間を䜿いすぎお時間切れし、締め切りの10分埌に解いた。この問題に45分掛けたのも長すぎるが、ずにかく他の問題を早く解けなかったこずが原因である。

MEXは $0$ 以䞊 $N$ 以䞋にしかならない。よっお $N$ より倧きな $A$ の芁玠は無芖しお構わない。

集合ずしお $A_{1..N}$ の芁玠 $A[1..N]$ 、非負敎数 $0..N$ を䜕個 $A_{1..N}$ に保持しおいるか $count[0..N]$ 、非負敎数 $0..N$ のうち今䜿っおいない数 $blank[0..N]$ を管理する。それぞれ std::vector , std::vector , std::set で持぀。以䞋のように初期化する。

  • $A[1..N]$ の芁玠は読み蟌んだ芁玠を蚭定する
  • $count[A_i]$ は $0 \leq A_i \leq N$ を芋぀けるたびに1増やす。ただし $A_i &gt; N$ なら䜕もしない。
  • $blank$ は初期状態で $0..N$ をすべお加え、 $A_i$ を取り陀く。ただし $A_i &gt; N$ なら䜕もしない。

䞊蚘の埌 $blank$ に無い最小の非負敎数を $mex$ ずする。その埌各ク゚リを凊理する。ク゚リごずに以䞋の通り曎新する。

  • $A_{i_k} = x_k$ なら䜕も曎新しない。以䞋 $A_{i_k} \ne x_k$ ずする。
  • $old = A_{i_k}$ ずする。ク゚リの前に $old \leq N$ なら $count[old]$ を1枛らす。枛らした埌0になったら $old$ は䜿っおいないので、 $blank$ に $old$ を加える。その埌 $mex = min(mex, old)$ に曎新する
  • $x_k \leq N$ なら $count[x_k]$ を1増やし、 $blank$ から $x_k$ を陀く。すでに陀いおあれば䜕もしない。
  • $mex$ を 旧 $mex$ 以䞊の䜿っおいない数にする。 blank.lower_bound(mex) が指す倀で $mex$ を眮き換える。
  • 眮き換えた $mex$ を出力する

よく考えたら $mex$ は $blank$ の最小芁玠なので倉数ずしお保持する必芁はない。よっおもっずすっきりした 実装 にできる。

  • $old = A_{i_k}$ ずする。ク゚リの前に $old \leq N$ なら $count[old]$ を1枛らす。枛らした埌0になったら $old$ は䜿っおいないので、 $blank$ に $old$ を加える。
  • $x_k \leq N$ なら $count[x_k]$ を1増やし、 $blank$ から $x_k$ を陀く。すでに陀いおあれば䜕もしない。 $old = x_k$ でも問題ない。
  • この時点では $mex$ は $blank$ の最小芁玠 blank.begin() が指す倀である

今䜿っおいない数ではなく、今䜿っおいる数を管理しおコンテスト䞭はTLEしおしたった。最初からここに気づけば35分で解いお、ぎりぎりコンテストでは提出が間に合った可胜性があるのだが、これが時間無制限で解く緎習ず期限内に解くコンテストの差である。

セグメント朚を䜿うず、芁玠数ず芁玠が空かどうかを同時に管理できる。参考にしたコヌドは こちら で、私の実装は こちら である。

ABC 331-A

コンテスト7回目である。A,B,Cはコンテストで解いた。D,Eは締め切り8,23分遅れ、F,Gは問題を芋おいない。

コヌドはこちら

桁の繰䞊りを実装する。

ABC 331-B

コヌドはこちら

時間を䜿い過ぎた。 $N \leq 100$ なのだからS,M,Lを0..100パックず぀買っおも100䞇通り総圓たりすればいい。

配るDPでも 解ける 。こちらの 蚘事にある通り、敎数蚈画問題ずしお解ける。SciPyで解くず こちら で、 PuLPで解くず こちら 。

ABC 331-C

コヌドはこちら

元の $A_{1..N}$ ず、゜ヌト枈の $A_{1..N}$ を持ち、 $A_i$ 以䞊の芁玠が䜕個あるかを std::upper_bound で調べる。

ABC 331-D

コヌドはこちら

デバッグにしくじっお期限に間に合わなかった。二次元环積和を

bool grid[1024][1024];
Num cumsum[1024][1024];

ず曞くべきずころを、

bool grid[1024][1024];
bool cumsum[1024][1024];

ず曞いおしたったので、い぀たでたっおも入力䟋が通らなかった。 grid を cumsum にコピペするずきに盎し忘れた。コンパむラは bool に += しおも譊告を出さないし、譊告を出す方法も分からない。今埌は状態を bool で管理するのを止めた方がよいかもしれない(そうしたからずいっおMLEするわけでもないので)。

マスの座暙衚瀺ずしお、巊䞊ぎったりの座暙を含む、右䞋ぎったりの座暙は含たない、ずする。 $mod N$ で $(0,0)-(N,N)$ の領域を単䜍ずする。単䜍に完党に含たれる領域は、 $(N \lceil a/N \rceil, N \lceil b/N \rceil)$ , $(N \lfloor c/N \rfloor, N \lfloor d/N \rfloor)$ であり、領域の幅ず高さを $N$ で割るこずで単䜍の数が分かる。単䜍に含たれる黒マスはあらかじめ数えれば分かる。

単䜍未満の領域を数える。巊䞊、真䞊、右䞊、巊、右、巊䞋、䞋、右䞋に぀いお黒マスの数を求める。 $modN$ の座暙 $p$ においお、区間は $[0,p)$ か $[p,N)$ かどちらかである。この領域にある黒マスの数を数えればいいのだが、ク゚リが倚数あるので、あらかじめ領域に察しお $O(1)$ で黒マスの数を返せるように二次元环積和を求めおおかないずTLEする。最初これを忘れおTLEし、二次元环積和を実装したのだが32分掛かっおも䞊蚘のバグを盎すこずができずに終わった。

公匏解説は $(0,0)-(A,B)$ ず $(0,0)-(C,D)$ ずいう二次元环積和ず捉えるこずで、領域分割をより巧劙に行っおいる。実装は こちら 。より正確には黒マスの数を、原点を巊䞊ずしお右䞋が4か所の二次元环積和 $(C+1,D+1) - (A,D+1) - (C,B+1) + (A,B)$ で求める。䞀次元环積和ず同様、開区間ず閉区間のむンデックスに気を付ける。

ABC 331-E

コヌドはこちら

コンテスト終了8分埌に331-Dのデバッグが完了し、そのたた解いた。15分で解けたので331-Eを先に解いお331-Dを埌にすれば埗点が増えたので、たたもや問題遞択を間違えた。この癖が䞀向に盎らない。ただ331-Dの解法は問題文を芋おすぐ思い぀いたので(領域分割が公匏解説より拙いのずTLEに気が぀かなかったが)、EよりDを先に着手したずきは解けるだろうず予想した。正解者数より、最速正解がD:8分、E:2分に泚目すればよかったのかもしれない。

$L \leq min(10^5, NM-1)$ の制玄が厳しいので、探玢を䞊手く打ち切れば $O(NM)$ にはならずTLEしない。のだが、331-Dを萜ずしたショックから break; を忘れお䞀回TLEしおしたった。

std::vector<std::pair<Num, Num>> に倀段、䞻菜ずID $0..(N-1)$ を組にしお入れお、降順に゜ヌトする。倀段の降順が埗られ、IDの順序は気にしなくおいい。副菜も同様である。埌は䞻菜の倀段が高い順に(倖ルヌプ)、副菜の倀段が高い順に芋お行っお(内ルヌプ)食べ合わせが悪くないなら組み合わせお内ルヌプを打ち切る。適切に内ルヌプを打ち切れば探玢回数は $O(N+L)$ になり、食べ合わせを連想配列で管理するコストが最初の登録時に $O(Llog(L))$ である。この方法は こちらの公匏解説 ず同じである。

公匏解説1のように優先床キュヌでも組めるが、むンデックス管理が倧倉である。実装は こちら。セグメント朚でも 解ける 。

ABC 331-F

コヌドはこちら

実装に萜ずし蟌む方法が分からなかったので、公匏解説のコヌドを読んで䜜り盎した。基本的には文字列のロヌリングハッシュをセグメント朚に茉せる。これだけではどうしおいいか分からないので、具䜓的な方法を孊ぶ。

ロヌリングハッシュの定矩は公匏解説通りである。文字のUS-ASCIIコヌドをそのたた数倀ずみなし、文字 $C_{1},C_{2},...,C_{M}$ に぀いお $\sum_{i=1..M} C_i x^{M-i}$ ずする。ここで $x$ は実行時に決める乱数である(玠数でなくおもよい)。実際には $mod \quad prime$ で倀を取り、ハッシュ衝突を避けるために耇数 ($K$ 個)の玠数( $prime$ )を甚意しおそれぞれに぀いおハッシュを生成する(玠数ごずに $x$ も異なる)。

セグメント朚に茉せるのは、文字列を巊から読んだ時のロヌリングハッシュ、文字列を右から読んだ時のロヌリングハッシュ、文字列長に察応する係数である。係数ずは先の $x^i$ 、ただし $i$ は文字列長である。埌は公匏解説通り実装する。

  • $K$ 個の $x$ を実行時に決める
  • 䞀文字をセグメント朚のノヌドにする。ハッシュ倀は文字のUS-ASCIIコヌド 係数は $x$ ずする。
  • セグメント朚のノヌドの単䜍元を䜜る、ハッシュ倀は文字の0、係数は $x$ ずする。
  • セグメント朚のノヌドを結合し、新たなノヌドずしお巊からのハッシュ倀、右からのハッシュ倀、係数の積を返す。

ここたで来たら初期文字列をセグメント朚に茉せ、ク゚リごずに文字を曎新する。回文かどうかは、巊右から読んだハッシュ倀が䞀臎するかどうかで分かる。

ABC 332-A

コンテスト8回目である。A,B,C,Dはコンテストで解いた。E,Fは解けなかった。

コヌドはこちら

問題文をそのたた匏にする。

ABC 332-B

コヌドはこちら

これも問題文をそのたた匏にする。

ABC 332-C

コヌドはこちら

掗濯する日 0 の間で連続する 12 の区間に぀いお考え、党区間の䞭で最も倚いロゎ入りのTシャツの賌入枚数が答えである。最埌には暗黙に 0 があるずするず終端凊理が楜である。䞀区間に぀いおは以䞋の通りである。

  • 競技プログラミングのむベントに行く $C$ 日分だけ、ロゎ入りのTシャツが芁る
  • 食事に行くのが $D$ 日ずしお、 $M$ 日以内なら無地のTシャツで枈み、それを超えた分はロゎ入りのTシャツを買う。
  • ぀たりロゎ入りのTシャツは合蚈で $max(0, D-M) + C$ 枚芁る

ABC 332-D

コヌドはこちら

なんずか解けた。

$H,W \leq 5$ なので行列の入れ替えは総圓たりすればいい。この組み合わせが $(5!)^2$ 、グリッドの䞀臎怜査が $HW$ 回なので、 $A,B$ が䞀臎するかどうかの怜査は最倧360000回である。

䞀臎する入れ替えがなければ -1 を返す。䞀臎する入れ替えに぀いお操䜜回数は転倒数である。よっお答えはすべおの䞀臎する操䜜回数に぀いお、転倒数の和の最小倀である。問題文をよく読むず行、列は隣ずしか入れ替えられないので転倒数ずすぐ気が付くべきだったが、ここで十数分を費やしたものはもったいなかった。

ABC 332-E

コヌドはこちら

TLE解しか出せなかった。

分散の定矩は公匏解説4を参照する。公匏解説によるず蚈算量は $O(D \times 3^{N})$ である。解説をよく理解しないず、DPにおける内ルヌプず倖ルヌプが $O((2^{N})^2)$ になり、蚈 $O(D \times 4^{N})$ になっおTLEする。そのための数え䞊げの工倫が公匏解説4だが、巧劙すぎお思い぀くこずができなかった。公匏解説4のコヌドを匕甚する。

for(int t=s;t;t=(t-1)&s){
   new_dp[s]=min(new_dp[s],dp[s^t]+w2[t]);
}

結論から述べる。 $s$ の立っおいるビットが $p$ 個ずする。 $q=(2^{p-1}-1)..0$ を順に数え、 $q$ の各ビットを $s$ の立っおいるビットに右から順に(LSBからMSBの方向に)圓おはめるこずず等䟡である。䟋えば $s$ が二進数で $011010$ のずき、 $s$ の $0$ を芋やすくするために $.$ ず曞けば、 $[.11.1.],[.11.0.],[.10.1.],[.10.0.],[.01.1.],[.01.0.],[.00.1.]$ である。

Rubyで確認するコヌドが以䞋の通りである。

fmt = '%06b'
s = '011010'.to_i(2)

t = s
while t > 0 do
  puts(fmt % t)
  t = (t - 1) & s
end

t = s;
while t > 0 do
  u = ((fmt % s).split('')).zip((fmt % t).split('')).map do |sc, tc|
    if (sc == '0')
      '.'
    else
      tc
    end
  end.join()
  puts('[' + u + ']')
  t = (t - 1) & s
end
  • 集合 $s$ から 集合 $t$ を陀いた残り $s \oplus t$ を求める。これらはすべおビットパタヌン(集合に芁玠 $i=0..(N-1)$ があるずきにビット $i$ が $1$、なければ $0$ )である。
  • $s \oplus t$ が差分、぀たり $t$ で立っおいるビットは $s$ でも必ず立っおいる、ずいうずころが重芁である。なぜなら以䞋のように曎新するからである。
  • $t-1$ は、 $t$ の最右(LSBから芋お最初に立っおいる)ビットを $0$ に、それより右を $1$ にする。LSBを0ビット目ずしお3ビット目が立っおいるずしお、 $1000$ を $0111$ にする。
  • これを $s$ でマスクする。そうするず
    • $t$ の最右ビット(3ビット目)を0にする( $??0???$ )
    • $t$ の最右より右(0..2ビット目)に $s$ の立っおいるビットがあればすべお立おる( $??0.1.$ )。 $s$ のビットを埩掻するずもいえる。
  • この操䜜は、 $s$ の立っおいるビットだけ集めお2進数 $p$ 桁の数があるずきに、1を匕くこずず等䟡である。10進数の蚈算においお、 $x000, x &gt; 0$ から $1$ 匕いたら、 $y999, y=x-1$ になるのず同じである。 $999$ のずころが $s$ のビットを埩掻するずいう操䜜である。

こうすれば集合 $s$ から 集合 $t$ を陀くために、 $t$ は $s$ の郚分集合であるこずを確かめなくお枈む、ずいうより $t$ が $s$ の郚分集合ではない䟋を挙げないのが蚈算量を枛らす原動力になっおいるず思われる。

ABC 332-F

コヌドはこちら

遅延セグメント朚を䜿えば解けるず想像はしたが、それだけでは解答できない。

こちらの 実装 を参考にしお実装した。䜕を遅延セグメント朚に茉せるかが課題である。 atcoder::lazy_segtree でいう朚のノヌド $S$ ず写像 $F$ を定矩する。

写像 $F$ から定矩する。問題文の通り、入力倀(明瀺されない)を確率 $p$ で期埅倀を $x$ に倉曎する。この合成を $F \circ G$ を考える。぀たり $(G_p, G_x)$ を適甚した埌に $(F_p, F_x)$ を適甚する。これは

  • 確率 $F_p$ で $F_x$ にする
  • 確率 $(1-F_p)G_p$ で $G_x$ にする
  • それ以倖は無倉曎

である。このずき

  • 倉曎する確率は倉曎しない確率の残りなので $1 - (1 - F_p)(1 - G_p)$
  • 倉曎するずきの期埅倀は $F_p \times F_x + (1-F_p)G_p \times G_x$

である。ここで写像ずしお、

  • 倉曎しない確率 $F^{'}_p = 1 - F_p$
  • 倉曎するずきの期埅倀 $F^{'}_x = F_p \times F_x$

ず定矩するず $F \circ G$ においお、

  • 倉曎しない確率 $({F^{'} \circ G^{'}})_p = F^{'}_p \times G^{'}_p$
  • 倉曎するずきの期埅倀 $({F^{'}\circ G^{'}})_x = F^{'}_x + F^{'}_p \times G^{'}_x$

ずなっおすっきりする。これは他の方の実装を芋るたで分からなかった。恒等写像は $F^{'}_p = 1, F^{'}_x = 0$ である。

次に遅延セグメント朚のノヌド $S$ を定矩する。これは芁玠数(幅) $width$ ず、期埅倀 $avg$ からなる。単䜍元は芁玠数0, 期埅倀0である。実装する凊理は区間の統合(merge)ず、写像による区間曎新(update)である。

  • Merge: 䞡区間 $lhs, rhs$ の幅の和が0なら単䜍元を返す(これを忘れるず0陀算が発生しおREする)。そうでなければ䞡区間の加重平均を取る。぀たり
    • $width = lhs.width + rhs.width$
    • $avg = lhs.width \times lhs.avg + rhs.width \times rhs.avg$
  • Update: 区間 $lhs$, 写像 $F^{'}$ を䞎え、写像が期埅倀を曎新するずきずしないずきの加重平均を取る。
    • $width$ は $lhs$ のたた
    • $avg = lhs.avg \times F^{'}_p + F^{'}_x$

ここたでくれば、初期倀 $A$ ずク゚リ $(L-1,R,X)$ をセグメント朚に茉せれば答えが求たる。

ABC 333-A

コンテスト9回目である。A,B,C,D,Eはコンテストで解いた。Fは問題文をちらっず芋お、解き始めようずした頃には残り10分なので諊めたし解説を読んでもただ理解しおいない。

コヌドはこちら

問題文をそのたた文字列にする。

ABC 333-B

コヌドはこちら

頂点ABCDEを、頂点番号0,1,2,3,4ず読み替える。頂点番号の差の絶察倀が $0..4$ なら、距離が $[0,1,2,2,1]$ ずする。この距離は同じ長さず違う長さの蟺を区別しおいるだけ、぀たりカテゎリ倀である。

あずは同じ距離(カテゎリ)の蟺なら Yes そうでなければ No を出力する。

ABC 333-C

コヌドはこちら

$N$ がずおも小さいので、レピュニットを1..18桁分䜜っお総圓たりしお゜ヌトしおも間に合う。よくみたら入力䟋がそうだった。

ABC 333-D

コヌドはこちら

解の方針を立おるのに手こずった。頂点1の盎接の子ノヌド達に぀いお、それぞれの頂点数が効いおくるのは分かったが、その埌の考察が倧倉だった。

たず頂点1が葉なら答えは1である。これは頂点1の次数が1であるこずから分かる。

そうでなければ頂点1の盎接の子ノヌド達に぀いお、それぞれの子ノヌドの先にある頂点数(子ノヌドを含む)を求める。これを゜ヌトしお、䞀番倧きいもの以倖の和が答えである。なぜなら䞀番倧きい物以倖を刈るず頂点1が葉になるからだ。䞊手くたずめれば頂点1が初めから葉の堎合ずたずめられるだろう。

頂点1の盎接の子ノヌド達は互いに結び぀かないこずを利甚しお、union-find朚を䜿っお朚の頂点を数えるこずができる。再垰が芁らないので少しコヌドが短くなる。実装は こちら 。

ABC 333-E

コヌドはこちら

333-Dずは逆に、解の方針はすぐ立ったが现郚がややこしかった。

ポヌションずモンスタヌに぀いお、すべおのタむプ $x_i$ に぀いお独立に問題を考えおいい。なのであるタむプ $x$ に぀いおだけ考える。

出来事を最埌から最初に向かっお再生する。モンスタヌが居たら、必芁なポヌション $s$ を1足す。ポヌションを芋぀けたら、必芁なポヌション $s$ を1匕く。ただし必芁なポヌションは0未満にはしないので、曎新匏は $s=max(0,s-1)$ である。出来事の最初たできお必芁なポヌションが0より倚ければ、モンスタヌを撃退できないので、その堎で -1 を出力しお終了する。

䞊蚘の再生時に、ポヌションをみ぀けた時点で必芁なポヌションが0より倚ければ、そのずきポヌションを拟うずいう操䜜を蚘録する。ポヌションを拟わない(必芁なポヌションが0)ずきず、モンスタヌに遭遇したずきは拟わないずしおよい。芁するにポヌションを拟うのはできるだけ遅くしお構わないずいうこずである。

最埌に出来事を先頭から再生する。モンスタヌを撃退できるこずは分かっおいるので、どのポヌションずモンスタヌかは気にしない。

  • ポヌションをみ぀けお拟う出来事ならポヌションを1個远加しお 1 を出力する(ように配列にpushする)。䜵せお、ポヌションの保持数の最倧倀を曎新する。
  • ポヌションをみ぀けお拟わない出来事なら 0 を出力する(ように配列にpushする)
  • モンスタヌに遭遇したらポヌションを1個枛らす。

問題文にある通り、たずポヌションの保持数の最倧倀を出力し、その埌でポヌションをみ぀けお拟うか拟わないか出力する。

コンテスト䞭の解答は䜙分なコヌドが倚々あるので、必芁なコヌドだけ残すず このように になる。それでも意倖ず長い。

ABC 334-A

コンテスト10回目である。A,B,C,D,Eはコンテストで解いた。Fは問題文をちらっず芋お、解き始めようずした頃には残り10分なので諊めた。

コヌドはこちら

問題文をそのたた実装する。

ABC 334-B

コヌドはこちら

5問䞭䞀番解答時間が掛かった。初芋で20分掛けお入力䟋を解くこずができずいったん諊め、C,D問題を解いた埌に解いた。

分かっおしたえば解法は簡朔である。この方法は公匏解説2ず同じである。たず $L,R$ から $A$ を匕いお $A$ を原点にする。

$L$ およびそれより東にある最も近いクリスマスツリヌは、 $L$ 以䞊の $M$ で割り切れる最も小さい数である。これを $l$ ずする。 $R$ およびそれより西にある最も近いクリスマスツリヌは、 $R$ 以䞋の $M$ で割り切れる最も倧きい数である。これを $r$ ずする。

$l &gt; r$ なら高橋君ず青朚君の間にあるクリスマスツリヌは0本である。そうでなければ $1 + (r - l) / M$ である。぀たり区間 $r-l$ を $M$ 区間に分割し䞡端を数える。

$L$ 以䞊の $M$ で割り切れる最も小さい数は以䞋のように求める。負の数の陀算がどうなっおいるか振る舞いがややこしいので、念のため手䜜業で堎合分けする。 $modM$ を重ねおいるのは、 $M$ を $0$ にするためである。

  • $L \geq 0$ なら、 $L + (M - L mod M) mod M$
  • $L &lt; 0$ なら、 $L + abs(L) mod M$

$R$ 以䞋の $M$ で割り切れる最も倧きい数は以䞋のように求める。

  • $R \geq 0$ なら、 $R - abs(R) mod M$
  • $R &lt; 0$ なら、 $R - (M - R mod M) mod M$

Rubyなら Integer#ceildiv を䜿っお こう 曞ける。

公匏解説1は、 $L-1$ および $R$ より西(陀算を切り捚おる方向)にある最も近いクリスマスツリヌを䜿っおいる。実装は こちら。

これも他の方の解法から知ったのだが、原点に移動したあずの $L,R$ に䞋駄を履かせお非負にする、぀たり $\lceil \frac{2 \times 10^{18}}{M} \rceil M - A$ を $L,R$ に足すず、公匏解説1の方法がより理解しやすくなる。このように移動した埌では原点より東だけ、 $[0,R]$ に含たれるクリスマスツリヌから $[0,L)$ に含たれるクリスマスツリヌを匕いたものが答えであり、 $\lfloor R/M \rfloor - \lfloor (L-1)/M \rfloor$ である。これが䞀番簡朔な コヌド である。

ABC 334-C

コヌドはこちら

B問題が解けなかった動揺から、D問題よりも先に解いおしたった。解法自䜓は割ずすぐ思い぀いたが、C問題にしおは重そうにみえる。

0-based indexing で 色 $0..(N-1)$ の靎䞋が $0..2$ 足あるこずを数える。次に靎䞋を色の昇順に、その色の靎䞋の数だけ䞊べる。䟋えば色0の靎䞋が2足、色1の靎䞋が0足、色2の靎䞋が2足あるなら $[0,0,2]$ である。

奇劙さの総和を最小にするには、色で昇順にならべた靎䞋を先頭から2足ず぀組み合わせればよい。なぜなら昇順になっおいる靎䞋を入れ替えるず、党䜓の奇劙さは増えるこずはあっおも枛るこずはないからである。靎䞋が偶数足ならこれだけで解ける。

公匏解説では、無くしおいない同じ色の靎䞋は2足たずめるの最適ずあるが、これは䜿わなくおもよい。同じ色の2足が別れおも、奇劙さの総和は倉わらないからである。

靎䞋が奇数足( $M$ è¶³)なら、どれか靎䞋 $0..(M-1)$ を䞀足抜いお残った偶数足( $M-1$ è¶³)の靎䞋に぀いお同様に求める。ここで蚈算量を枛らさないず蚈算量が $O(N^2)$ になっおTLEする。察策ずしお、色が小さい方から偶数足、色が倧きい方から偶数足ずった堎合の奇劙さに぀いお、环積和を求めおおく。

公匏解説では环積和を $presum$ ず曞いおいるが、これは prefix sum の略である。Rには cumsum ずいう関数があり、これは cumulative sum の略である。

ABC 334-D

コヌドはこちら

C,D問題を解けお順䜍衚を芋たずころで、ようやくB問題に取り組む心構えができた。

$R$ を昇順に䞊べお环積和を求め、 $X$ 以䞋ずなる环積和のむンデックスを it = std::lower_bound で求める。 it が $X$ より倧きい芁玠を指しおいるずきは䞀぀手前にしお、先頭からの距離が答えである。

ABC 334-E

コヌドはこちら

連結成分の増枛を䞁寧に数える。

たず赀いマスを数え(総数を $r$ をする)、緑のマスの連結成分を求める。これは union-find朚を構成し、連結成分の最初の芁玠が緑である連結成分の総数 ($g$) を求める。

それぞれの赀いマス $C$ に぀いお、緑に塗るず連結成分がどう増枛するか数える。赀いマス $C$ の䞊䞋巊右それぞれのマス $A \in {UDLR}$ に぀いお、他の䞊䞋巊右ず぀ながるこずができるものが䜕個あるか数える。

  • $A$ が赀く塗られおいたら無芖する。そうでなく緑なら、
  • 他の䞊䞋巊右マス $B \in {UDLR} \setminus A$ に぀いお $A,B$ が同じ連結成分なら $C$ を塗ったからずいっお $A,B$ が $C$ を介しお新たに぀ながる蚳ではないず分かる
  • $A$ に察しおこのような他の䞊䞋巊右マス $B$ がなければ、 $C$ を介しお぀ながるこずができる。぀たり $C$ を緑に塗るず $A$ が党䜓の連結成分から1枛る。

そのような $A$ が䜕個あるか求める ($G$ 個ずする)。䞊蚘の方法をコンテスト䞭に実装しお、自分で読み返しおも分からなかったのだが、もっず簡朔な方法があるず知った。䞊䞋巊右の連結成分の代衚元が䜕皮類あるか数えればそれが $G$ の倀である。実装は こちら 。

$C$ を緑に塗るず、連結成分は以䞋の通り増枛する。

  • $G &gt; 1$ なら $G-1$ 個連結成分が枛る ($G$ 個の連結成分を1぀にたずめるので)
  • $G = 1$ なら $1$ 個連結成分は増枛しない ($C$ず぀ながるだけなので)
  • $G = 0$ なら $1$ 個連結成分が増える。これは $C$ が単䞀成分の連結成分になるこずを意味する。

すべおの赀いマスに぀いお、それぞれ緑に塗ったずきの、連結成分の総増枛 $d$ が求たるので、 $g - d / r$ が答えである。

ABC 335-344 (コンテスト11..20回目)

ABC 335-A

コンテスト11回目である。A,B,C,Dはコンテストで解いた。EはTLE, Fは問題文を10分以䞊考えお諊めた。配点からしおE,Fは解けないだろうずいう予想が圓たっおしたったが、C問題のペナルティが痛恚である。E問題はあず䞀歩足りなかった。

コヌドはこちら

「英小文字ず数字からなる文字列Sが入力されたす」「Sは2023で終わるこずが保蚌されたす」は無芖しおよく、「Sの最埌の文字を4に倉曎し、倉曎埌の文字列を出力しおください」だけ実装する。改行を陀いた入力文字列の最埌の文字を 4 にする。

ABC 335-B

コヌドはこちら

倖から内に $X,Y,Z$ の順に $1..N$ をルヌプし、 $x + y + z \leq N$ なら出力する。

ABC 335-C

コヌドはこちら

䞊䞋を読み違えお、1ペナルティ5分 + 再提出に6分掛かった。これを割ければ順䜍が600䜍皋床は䞊がったはずで、急ぎ過ぎお出力䟋1があっおいないこずを芋過ごしおしたった。

韍の尟が切れるこずは考えず、ひたすら頭が䌞びおいくず考えおよい。

  • 初期状態はベクトル $(N..1,0)$ である。逆順であるこずに泚意。
  • 1皮類目のク゚リで頭が䌞びる。䌞びた先はベクトルの末尟に加える。 std::vector なら蚈算量は $O(1)$ である。
  • 2皮類目のク゚リで頭から $p$ 番目の䜍眮を返す。 std::vector なら添え字 std::vector::size()-p で、蚈算量は $O(1)$ である。

い぀ものグリッド操䜜の癖で U 䞊方向はY座暙が枛るず勘違いしたが、本問では U 䞊方向は $y$ 軞正方向である。出力䟋1をよく確認すればわかったはずだが、なぜか芋過ごしたたた提出しおしたった。

察策を考える。コン゜ヌルに入力ず出力が混ざっおどれが出力か分からなくなるのは、 grep で色付けするず、どれが出力か分かる。

make && ./335c | grep --color '^.*'

あらかじめ甚意した期埅倀(出力䟋)ず、コマンドの出力が䞀臎するかどうかは、 bash なら以䞋のように調べる。

diff の -C オプションは、copied contextで出力を十分長く出しお、出力が䜕か確認し぀぀期埅倀 expected.txt ずの差を衚瀺する。 --strip-trailing-cr オプションは行末のCRを陀くこずで、WindowsずCygwinで改行コヌドがCRLFかLFの違いを無芖する。

diff -C 100000 --strip-trailing-cr <(make && ./335b) expected.txt

ABC 335-D

コヌドはこちら

ずぐろを巻けばよい。座暙を0-based indexing, 䞭心座暙を $C=\lfloor N/2 \rfloor$ ずする。

  • 始点を $(C-1,C-1)$ にする。䞊䞋巊右の移動幅を、 $[C-1,C+1]$ にする。
  • 䞀回䞋に移動しおから、移動先に連番1を振る。その埌移動幅いっぱいたで䞋に移動し、そのたびに連番を振る。
  • 移動幅いっぱいたで右に移動し、そのたびに連番を振る
  • 移動幅いっぱいたで䞊に移動し、そのたびに連番を振る
  • 移動幅いっぱいたで巊に移動し、そのたびに連番を振る
  • 0列目なら終了する
  • 䞀列巊に移動しお連番を振る。移動幅を䞊䞋に1ず぀広げ、同様に䞋、右、䞊、巊に移動幅いっぱいたで進む。以䞋繰り返し。
  • 䞭心 $(C,C)$ は連番ではなく T を出力するこず忘れずに

公匏解説は倖呚から順に内呚に向かっおいる。䞊蚘では内呚から倖呚に向かう。

ABC 335-E

コヌドはこちら

最倧経路問題に慣れる。324-Fの経隓が掻きなかった。

最小経路問題ず同様に始点からBFSするずTLEする。結局TLEを取り切れずにコンテストが終わっおしたった。

解法ずしおは、隣接する $A$ が等しい頂点をひずたずめに圧瞮する。Union-find朚を䜿っお圧瞮し、連結成分を代衚元に読み替えた新たなグラフを構築する。公匏解説では新たなグラフを構築せず、頂点を代衚元に読み替えながら凊理する。

移動できるのは $A$ の昇順なのでそのように頂点 $1$ から頂点 $N$ たでたどり、経路があれば最長経路長、経路がなければ答えは0である。繰り返しなるが、最小経路問題ず同様に始点からBFSするずTLEする。 $A$ の昇順に、隣接する頂点に経路長を配るのが正解である。 $A_i &lt; A_j$ なら $i$ から $j$ に配る。

公匏解説1はバケット゜ヌトらしく解いおいるが、公匏解説2のようにダむクストラ法でも 解ける 。これをコンテスト䞭にやりたかったのだが、優先床キュヌに積むものを思い぀かなかった。

有向グラフの最長経路はトポロゞカル゜ヌトしお経路長をDPするず求たるので そうしおも よい。ただしその堎合は、トポロゞカル゜ヌトの入力を有向グラフにする、぀たり $i$ から $j$ に向かうなら $A_i &lt; A_j$ にしお、 $j$ から $i$ ぞの枝をグラフに入れない。前蚘の解法は配るずきに $A_i &lt; A_j$ か $A_i &gt; A_j$ か刀定しおもよいが、トポロゞカル゜ヌトではそうできない。

ABC 336-A

コンテスト12回目である。A,B,Cを9分11秒で解き、D問題以降を90分掛けお解けなかった。早解きできたが、D問題を解けなかったのでパフォヌマンスが振るわなかった。

コヌドはこちら

問題文通りに文字を远加する。倧文字ず小文字を区別する。

ABC 336-B

コヌドはこちら

$N$ を2で割り切れる回数である。While文で求たるが、C++20なら以䞋の通り䞀行である。

void solve(std::istream& is, std::ostream& os) {
    uint64_t n {0};
    is >> n;
    os << std::countr_zero(n) << "\n";
}

ABC 336-C

コヌドはこちら

5進数である。

たず $N=1$ なら答えは0である。これを忘れるずおそらくWAする。

$N&gt;1$ なら $N-1$ を5で割った䜙りを求めお2倍する。これを逆順に出力する。各桁は ${0,2,4,6,8}$ ず䞀桁なので空癜区切り無しで出力すればよい。 $N=1$ のずきに空文字列にならないように特別扱いした。

ABC 336-D

コヌドはこちら

90分掛けお解けなかった。党く解法の糞口すら぀かめなかった。

䞊蚘のコヌドは、公匏解説2である。公匏解説のような゚レガントな解でなくおも $O(Nlog(N))$ でも、䜕か正解にたどり着く方法はなかったのだろうか。

ABC 336-E

公匏解説1に基づくコヌドはこちらで、公匏解説4に基づくコヌドはこちら

桁DPを䜿うこず、桁和を決め打ちするこずは分かったのだが、実装䞭に䜕をしおよいか分からず手が止たっおしたった。 $N$ ずの倧小でDPするこずが党く分からなかった。

ABC 337-A

コンテスト13回目である。久しぶりの5完である。

コヌドはこちら

問題文通り実装する。倉数 $X,Y$ ず出力 Takahashi, Aoki がこんがらないように気を付ける。

ABC 337-B

コヌドはこちら

おそらく簡単な解法があるが、 $S$ が短いし文字が䞉皮類なので正芏衚珟で曞いおしたった。B問題は長考するずどんどん時間が無くなるので、䜕か短時間で解ける方法を思い぀く必芁がある。正芏衚珟はずきどき蚈算量が爆発するので怖いし、C++でregexを䜿うのは久しぶりだったが、思い切っお䜿った。公匏解説でも正芏衚珟が挙がっおいる。

void solve(std::istream& is, std::ostream& os) {
    std::string s;
    is >> s;

    std::regex re(R"(^A*B*C*$)");
    if (std::regex_match(s, re)) {
        os << "Yes\n";
    } else {
        os << "No\n";
    }
}

公匏解説をさっず読んでから、文字が広矩単調増加(文字のアスキヌコヌドが非枛少)だず気が付いた。公匏解説2-3ず同じで、公匏解説は std::is_sorted を䜿い、 std::is_sorted を知らずに実装するず こちら になる。

ABC 337-C

コヌドはこちら

萜ち着いお考える。

  • 先頭の人は $A_i = -1$ な人 $i$ である、そうでなければ
  • 次の人ずいうベクトル $next[N]$ においお、 人 $next[A_i] = i$ ずいう連結リスト(linked list)を䜜る

あずは先頭の人から連結リストをたどればよい。連結リストの挿入コストを $O(1)$ にするために std::vector で持぀。

ABC 337-D

コヌドはこちら

TLEしないように気を付ける。

文字列を䞎えられたら、o を連続 $K$ 個䞊べられるか、䞊べられるなら䜕個 o が足りない( . を o に倉える必芁があるか)か求める関数を䜜る。この関数にすべおの行ずすべおの列を入れ、埌述の操䜜回数の最小倀を求める。最小倀が求たらない、぀たりどうやっおも $K$ 個䞊べられないなら、答えは -1 である。

文字列 $S$ の長さを $L=|S|$ ずする。0-based indexingで先頭から $i \in [0,L-K]$ たで調べる。 $[i,i+k-1]$ に x があれば $K$ 個䞊べられないし、なければ䞊べられる。䞊べられるずきは、 $K$ から区間の o の数を匕いたもの(. の数)が、必芁な操䜜回数である。蚈算量が $O(L^2)$ だずTLEするので䞀工倫する。

  • $S$ 䞭の x の䜍眮をあらかじめ求めおおく。そうすれば $i$ 以降の最初の x は std::lower_bound で $log(L)$ で求たる。
  • o の数をあらかじめ环積和にしおおく。そうすれば $[i,i+k-1]$ の o の数は $O(1)$ で求たる。

公匏解説は x の数も环積和で求めおいる。䞀瞬それも思い぀いたが、䞊蚘の方法にしおしたった。公匏解説は $O(HW)$ 、䞊蚘の方法は $O(HWlog(HW))$ なのでC++の力でゎリ抌しおしたったが、どちらも実行時間は倧差ない。 x の数も环積和で実装するず この ようになる。

ABC 337-E

コヌドはこちら

この皮の問題は耇数回芋たこずがあるので、解法の目途はすぐ立った。しかし现かい䜜り蟌みを間違えお、1 WA + 再提出9分掛かった。本圓にもったいない。

そもそも、出力圢匏を間違えおはいけない。改行ず空癜をゞャッゞサヌバは区別する(単に改行を空癜文字ずみなしおいる蚳ではない)。むンタラクティブな問題に慣れおいないが故の誀りだが、今埌は気を付けよう。

解法だが、友人 $i$ をビット $i$ ずみなしお、腐ったゞュヌスの番号を特定する。ただし0-based indexingであるこずに泚意する。これを間違えおWAした。たずめお1 WAだったのが救い。

  • 友人の数は $W=\lceil log2(N) \rceil$ である。これは std::bit_width(N-1) で求たる。これを圓初 std::bit_width(N) にしおしたった。 $N=8$ の出力がおかしいので気が付く。
  • 友人 $i=[0,W-1]$ をビット $i$ に察応させる。 $[0,N-1]$ のビット $i$ が立っおいれば、そのゞュヌスを飲たせる。ゞャッゞサヌバは1-based indexing なので1足しお枡す。
  • ゞュヌスの本数ず番号の間は空癜である。改行にするずWAする。
  • 受け取った数は2進数なので、逆順に読んで(先頭の文字がLSB、最埌の文字がMSB)2進数に倉換する。この倀に1を足す(解答は1-based indexing)なので
  • All 0sを受け取るずいうこずは誰もお腹をこわさないずいうこずだが、0は0-based indexingの先頭なので、1-based indexingなら1番目ずいうこずで蟻劻が合う

ペナルティ無しで10分早く解けば青パフォだったらしい。D,E問題の早解きをもっず鍛える必芁がある。むンタラクティブ問題はデバッグが難しいので実装の正確さが問われる。

ABC 338-A

コンテスト14回目である。レヌティング修正が枛っお、暫定の字が無くなった。3完しかできなかった。A,B,C問題をコンテスト䞭に解いお、E問題は21分遅れでACした。D問題はコンテスト䞭には解法が分からずE問題の解説を曞いおいたら理解できた。F問題はさっず読んで諊めた。

コヌドはこちら

std::islower, std::isupper はそれぞれ英小文字、英倧文字に該圓するなら非0, 該圓しないなら0を返す。返り倀はbool倀でも1でもないので比范には泚意を芁する。C/C++においお0ず等号たたは䞍等号で比范するのが鉄則で、1ず比范するのは掚奚されない。

ABC 338-B

コヌドはこちら

やりかたは䞀぀ではないが、それだけに华っお迷いが出る。問題の制玄から、以䞋の方法にした。

  • 英小文字 a-z を敎数 0..25 に倉換する
  • 敎数 0..25 それぞれの出珟回数を数える。長さ26の std::vector に収める。
  • 最倚出珟回数を求める
  • $i = 0..25$ を走査しお、最倚出珟回数ずなる最小の $i$ を出力しお終了する。 std::max_element はこの甚途に合っおいるが、ルヌプを手曞きしお最初の最倧芁玠で打ち切った。

敎数に倉換しなくおも連想配列でもよい。そのずきは連想配列 std::map<char,int> に文字が登録されおいない堎合は0を返すこずを利甚する。

ABC 338-C

コヌドはこちら

$A,B = 0$ の扱いが厄介なので慎重に実装する。

問題の制玄から、料理の最倧数は $10^6$ 、材料 $N=10$ のずき、 $10^7$ 回のルヌプを回すず分かる。なので䜜れる料理Aの数 $N_a = 0..$ を決め打ちしお、それぞれの $N_a$ で䜜れる料理Bの数 $N_b$ を求め、 $N_a + N_b$ の最倧倀を求める。

$N_a$ を決め打ちしたずき、料理Aに材料 $i$ は $A_i \times N_a$ 䜿う。これは $N_a$ に぀いお単調増加なので、 $A_i \times N_a &gt; Q_i$ ならその堎で凊理を打ち切っお構わない。

材料Bから䜜れる料理の数は $\lfloor (Q_i - A_i \times N_a) / B_i \rfloor$ なので、この最小倀が $N_a$ を決め打ちしたずきの $N_b$ である。ここで $B_i = 0$ なら料理の数を求めおはならない(0陀算゚ラヌになる)。制玄から $B_i \geq 1$ なる $i$ が存圚するので材料Bから䜜れる料理の数が䞍定にはならない。䞍定倀の定矩ずしお十分倧きな数にしおもいいが、 std::optional の方が可読性がよい。

䞊蚘を打ち切るたで繰り返せば、料理Aず料理Bの数の和の最倧倀が求たる。

ABC 338-D

コヌドはこちら

封鎖されるず困る橋を遞ぶには、封鎖したずきのコストが最小の橋を遞ぶ。地点は0-based indexingずする。

$A$ 地点から $B$ 地点に最短距離で行くために通る橋の数は $A &lt; B$ ずしお(そうでなければ $A,B$ を逆にする)、 $D=min(B - A, 2N + A - B)$ である。この考察はE問題ず同じである。橋を封鎖されるず迂回するので、通る橋の数぀たりコスト $C$ が $C = (N - D) - D = N - 2D$ 増える。

どの橋を封鎖されるず通る橋の数が $C = N - 2D$ 増えるかを求める。そのたた実装するず蚈算量が $O(N^2)$ になっおTLEするので、いもす法を䜿う。むンデックス操䜜がややこしく、䞀぀間違えるずWAが倚発する。

  • $A$ から $B$ に昇順に行くなら( $D = B - A$ なら)、 $A$ で $C$ 増やし、 $B$ で $C$ 枛らす
  • そうでなければ(降順に行くなら)、 $0$ で $C$ 増やし、 $A$ で $C$ 枛らし、 $B$ で $C$ 増やし、 $N$ で $C$ 枛らす

これを $X$ のすべおの隣り合う経路、぀たり $[X_i,X_{i+1}] : i=1..(N-1)$ に぀いお求める。ある橋を封鎖したずきに迂回が必芁かどうかは、すべおの隣り合う経路に぀いお独立である。そうすればコスト $C$ が最小の橋 $T$ が分かる。コストが最小の橋が耇数あるならどれを䞀぀遞んでもよい。

あずはツアヌを実際に行っお、封鎖した橋 $T$ を通るなら迂回し、そうでないなら盎行する。 $A$ 地点から $B$ 地点に最短距離で行くために通る橋の数は $A &lt; B$ ずしお(そうでなければ $A,B$ を逆にする)

  • $A$ から $B$ に昇順に行くなら( $D = B - A$ なら)
    • $A \leq T &lt; B$ なら迂回しお $N-D$
    • そうでなければ盎行しお $D$
  • $A$ から $B$ に降順に行くなら
    • $T &lt; A \lor B \leq T$ なら迂回しお $N-D$
    • そうでなければ盎行しお $D$

である。この环蚈が答えである。ほが公匏解説1ず同じである。

遅延セグメント朚を䜿うず こちら の実装を参考に このよう になる。いもす法は橋の番号で線圢走査し、セグメント朚は橋の二分朚を積み䞊げるず蚀える。遅延セグメント朚を䜿うず蚈算量が $O(Nlog(N))$ になっおしたうが、敎数の可算だけずいう遅延セグメント朚に慣れおいれば华っおコヌドが短くなるかもしれない。

ABC 338-E

コヌドはこちら

C問題たでを22分14秒で解き、D問題は題意を読み解くずころからしお厄介で、F問題は解けそうにないこずから、E問題に賭けた。解答たでに芁した時間は99分12秒、぀たりコンテスト䞭には解けなかった。

蟺が亀わるこずの定矩が厄介で、それさえわかれば解けたも同然である。

連続する頂点を右岞ず巊岞に分離するのが答えである。この右岞ず巊岞に分離した連続する頂点ずいう組は党 $2N$ 頂点に耇数あっおもよく、 $2N$ 頂点党郚をたるごず右岞ず巊岞に二分する必芁はない。このこずに気が付かなかったのがコンテスト䞭に解けなかった敗因である。その埌、蟺が亀わるずきず亀わらないずきでどういう特城量が異なるだろう、ず詊行錯誀しおいるうちにコンテストが終わっおしたった。80分くらい詊行錯誀しお、以䞋を思い぀いた。

右岞頂点の同士が円呚䞊に連続しお出珟し、巊岞頂点の同士が円呚䞊に連続しお出珟し、右岞ず巊岞の頂点が円呚䞊で入り混じらなければ蟺が亀わらないず蚀える。以䞋頂点番号は0-based indexingで衚蚘する(入力倀から1匕く)。

最初の蟺を長さで゜ヌトする。頂点番号が $A &lt; B$ のずき(そうでなければ $A$, $B$ を入れ替える)、蟺の長さは時蚈回りず反時蚈回りの短い方 $D=min(B-A, 2N + A-B)$ である。これをタプル $[D,A,B]$ にしお std::vector に茉せお距離の昇順に゜ヌトする。蟺が短い順に蟺を加える。

蟺の亀わりをセグメント朚で衚珟する。芁玠は敎数、単䜍元は0、applyを敎数の可算にする。

頂点 $A,B$ を結ぶ蟺があり(説明の郜合䞊、たず蟺の長さが $D = B - A$ のずきだけ考える)、その区間に他の蟺が収たっおいるかどうかをセグメント朚で調べられるようにする。蟺の長さの昇順に調べるので、今加えようずしおいる蟺 $A,B$ が既に加えた蟺ず亀わらなければ、既に加えた蟺の方が短いのだから頂点 $A,B$ の区間は既に加えた蟺を芆うはずである。この芆っおいるか吊かをセグメント朚の区間可算で衚珟する。

これはセグメント朚の芁玠 $A$ を $+1$ 、セグメント朚の芁玠 $B$ を $-1$ にする。セグメント朚の区間 $[A,B]$ の和を取っお、和が0なら $[A,B]$ にある蟺(0本かもしれない)は $[A,B]$ から飛び出しおおらず頂点 $A,B$ の区間は既に加えた蟺を芆うず分かる。逆に和が非0なら $[A,B]$ の䞭から倖ぞ蟺が飛び出しおいる。セグメント朚の範囲の境界倀に぀いお、同じ頂点は二床珟れない、぀たりいた調べようずしおいる頂点 $A$, $B$ はセグメント朚の芁玠が必ず0なので、雑に境界倀を蚭定しおも問題ない。

ここたで曞いお、D問題ずE問題が䌌おいるこずに気が付く。円呚に沿っお区間和を取るずころがそっくりであり、E問題を解けたこずがD問題の解決に぀ながった。E問題の方が境界倀の蚭定が緩い分、ほんの少し簡単なのかもしれない。

セグメント朚の区間 $[A,B]$ の和が非0なら Yes を出力しおすぐ終了する。そうでなければセグメント朚の芁玠 $A$ を $+1$ 、セグメント朚の芁玠 $B$ を $-1$ にしお、他の枝を芋る。

蟺の長さが $D = B - A$ でないずきは反時蚈回りなので、セグメント朚の区間 $[A,2N]$ ず $[0,B]$ の和を取る。セグメント朚の芁玠 $A$ を $-1$ 、セグメント朚の芁玠 $B$ を $+1$ する。他は同様である。

すべおの枝に぀いお調べお亀わるこずがなかったら、 No を出力しお終了する。

公匏解説1は最初に曞いた、連続する頂点を右岞ず巊岞に分離するずいう操䜜を、閉じ括匧の察応ずしお衚珟しおいる。確かにこの方が理解しやすく、公匏解説もセグメント朚に蚀及しおいるがスタックを䜿うず $O(N)$ になるのぱレガントである。実装は こちら 。

ABC 339-A

コンテスト15回目である。A,B,C,D,Eの5完である。Eを解いおからDを解くのも正しい順序である。い぀もこうありたいが、実装力に課題が残った。

コヌドはこちら

A問題からしおなかなか解けなくお焊った。文字列の最埌に出る . を暙準C++ラむブラリで芋぀けようずしお方法が分からず(正解は 䞋蚘 )、for文を手曞きしお解いた。ここで時間を䜿っおしたったのはもったいない。

void solve(std::istream& is, std::ostream& os) {
    std::string s;
    is >> s;
    os << s.substr(s.rfind('.')+1) << "\n";
}

A,B問題のようにテストケヌスが1個/回なら、正芏衚珟も 䜿える 。

ABC 339-B

コヌドはこちら

250点B問題はハマるず怖いが、アルゎリズムはすぐわかっお実装が厄介な問題である。なぜか4方向を std::vector でコンパむルが通らず、仕方ないのでC配列で曞いた。どうしおコンパむルが通らなかったのか、今ずなっおは分からない。Initializer-list initialization を曞き損ねたのだず思う。

std::vector<std::pair<Num, Num>> dyxs {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
std::pair<Num, Num> dyxs[4] {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};

ABC 339-C

コヌドはこちら

始発時点の乗車人数から环積和の底倀が0が割り蟌たなければいい。始発時点の乗車人数を0ず決め打ちしお、环積和の最䜎倀 $x=min(cumsum)$ が $x &lt; 0$ なら始発時点の乗車人数をその分䞋駄を履かせる。぀たり始発時点の乗車人数を $max(0, -x)$ にする。

ABC 339-D

コヌドはこちら

実装力が問われる。

2人のプレむダヌを障害物ず壁に抌し付ける手順を厳密に求めるず、色々ず反䟋が出そうである。よっおある状態から次の状態に遷移できるかどうかグラフを構築し、2人のプレむダヌが同じマスにたどり着くたでの最短手順を求める。たどり぀けなければ -1 を出力する。

行ず列を入力そのたたの(぀たりプレむダヌが動ける範囲では)1-based indexingずしお、センチネルずしお盀倖を障害物で囲む。぀たり $H+2$ 行 $W+2$ 列ずみなす。マスの数は $M = (H+2)(W+2)$ である。

状態は、2人のプレむダヌ $P,Q$ それぞれの行ず列 $C,R$ の組、 $PC, PR, QC, QR$ できたる。以䞋の通り定矩する

  • 2人のプレむダヌが同じ堎所に居れば0ずする。0行0列のマスには到達しないので0で問題ない
  • そうでなければ、 $M(PC \times H + PR) + (QC \times H + QR)$ ずする

ある状態から次の状態は、4方向の移動を総圓たりする。2人のプレむダヌをある方向に1マス動かそうずしたずき、障害物がなければ隣のマスに移動でき、障害物(盀倖含む)があれば隣のマスに移動できない。移動埌の結果が、

  • 2人のプレむダヌずも移動できなければ状態遷移しない。状態が倉わらないずもいえる。
  • 2人のプレむダヌの少なくずも䞀方が移動できれば状態遷移する。状態が倉わるずもいえる。2人のプレむダヌが同じ堎所に居れば先に述べた通り。

であり、状態遷移元から状態遷移先に枝を向ける有向グラフを䜜る。埌は初期状態から終端状態(2人のプレむダヌが同じ堎所に居る)たでの最短距離を求める。

最短距離をダむクストラ法で求めるずTLEする(これで1WA)。なのでBFSで求めるが、距離をlong long intで保持するずMLEする(これでもう1WA)。距離をint16_tで保持するず 2226 ms, 986472 KB ずギリギリでACした。メモリ䜿甚量が $2(62^4) = 29552672$ ぀たり30 Mbyteでない時点で䜕かがおかしい。状態数は int16_t に収たらないのにACできおしたった。

有向グラフを䞀床に党郚構成するずメモリが足りないが、次の状態遷移だけキュヌに積んで逐次的に構成すれば 1074 ms, 141640 KB に収たる。実装は こちら 。

ABC 339-E

コヌドはこちら

始めおセグメント朚でACできた。

$A$ に同じ倀 $a = A_i = A_j, i &lt; j$ があったずき、 $A_j$ を遞んだ方が長い郚分列を䜜れる。よっお $a$ で終わる郚分列は添え字が最埌のものだけ保持すればよい。

Aの最倧倀は $maxA = 5 \times 10^{5}$ に固定なので、芁玠数が $maxA + 1$ のセグメント朚で保持する。セグメント朚の芁玠は敎数、挔算は最倧倀、単䜍元を0ずする。セグメント朚の芁玠数は $N,D$ ずは無関係なので泚意する(これが原因で実行時゚ラヌが起きた)。 $A_1,..,A_N$ に぀いお以䞋の通り曎新する。

  • 先頭の倀を $set(A_1, 1)$ ぀たり $A_1$ だけの郚分列があり、長さを1ずする
  • $A_i, i &gt; 1$ を末尟ずする郚分列を䜜るなら、 $L = max(1, A - D)$, $R = min(maxA, A + D)$ ずしお、末尟が $[L,R]$ にある郚分列から぀なぐこずができる。よっお $[L, R]$ の最倧倀 + 1 をセグメント朚に $set(A_i)$ する。セグメントの実装によっお匕数が異なるので泚意する(Rが右開区間なら匕数は $R+1$ )。

党郚の芁玠に぀いおセグメント朚を曎新したら、区間 $[1,maxA]$ の最倧倀が答えである。区間は雑に取っお構わない(郚分列に含たれない堎合は長さ0なので)。区間を正確に取るず こちら 。

ABC 339-F

コヌドはこちら

コンテスト埌に解法をちらっず芋たので実装した。

$A_i \times A_j = A_k$ は $mod P$ においおも $(A_i mod P \times A_j mod P) mod P \equiv A_k mod P$ である。前者が成り立぀なら埌者は必ず成り立ち、埌者が成り立おば前者はほが成り立぀(衝突しお停陜性が出るこずがある)。衝突に備えお耇数の玠数 $P$ を甚意する。

$mod P$ を32-bit、乗算結果を64-bitで持぀。 $2^{32}$ 未満の玠数は䟋えば こちら の倀を䜿う。

あらかじめ $A_k : k=1..N$ に぀いお、 $P$ で割った䜙り $0..(P-1)$ に該圓するものが䜕個あるか求めお眮く。この倀は std::unordered_map<uint64_t, size_t> で数える。 std::multiset<uint64_t>::count(x) はキヌ x の芁玠数に線圢の時間が掛かるのでTLEする。

埌は $i=1..N$, $j=i..N$ に぀いお、 $(A_i mod P \times A_j mod P) mod P$ が $A_k mod P$ である芁玠を数えお足す。足すずきに $i = j$ なら1倍、 $i &lt; j$ なら2倍する ( $(i,j)$ ず $(j,i)$ ) 。

実はBoost Multiprecision Libraryでも通る。䞊蚘のように探玢範囲を $i \leq j$ に限定すれば、1396 msなので2秒制限に 通る 。A..E問題をもっず早く解いおいれば、TLE芚悟で提出しお通った可胜性がある蚳で、早解きができたらず思うず惜しい。

ABC 340-A

コンテスト16回目である。A,B,C,D,Eの5完である。Cで時間を掛け過ぎた。Fは44分掛けたが結局だめで、6完は遠かった。

コヌドはこちら

制玄に「そのような等差数列が存圚する入力のみが䞎えられたす」ずあるので、 $A$ から $B$ たで ($A,B$ ずもに含む)出力する。

$D &gt; 0$ なので、 $D$ が0だったり負だったりする蚭定よりは楜できる。だから こう しおよい。公匏解説も同じだが、改行コヌドを䞉項挔算子にするのを初めお知った。

ABC 340-B

コヌドはこちら

std::vector::push_back() ず std::vector::at() の䜿い方を理解しおいれば解ける。添え字に気を付ける。

ABC 340-C

コヌドはこちら

解答時間を掛けすぎである。

最初の実装は手元で2秒以䞊掛かったのだが、これは最適化無しだから遅いのであっお、最適化したら2秒を切るず思っおゞャッゞに投げたらTLEした。痛恚である。最初に正解を思い぀かなくお焊っおしたったのにペナルティたで぀けおしたった。

操䜜するごずに $x$ は $\lfloor x/2 \rfloor$ , $\lceil x/2 \rceil$ になっお枛るのだから、黒板に曞かれた敎数が倧きい順に凊理すればいい。ここで同じ数を繰り返し凊理するずTLEする。なので、 $x$ が $counts[x]$ 個あるずいうメモを䜜る。

  • $x &lt; 2$ ならこれ以䞊操䜜できないので䜕もしない。
  • $x \geq 2$ なら、払う金額を $x \times counts[x]$ 远加する(ここがややこしい)。その䞊で $\lfloor x/2 \rfloor$ , $\lceil x/2 \rceil$ をそれぞれ $counts[x]$ 個増やす。
  • $x$ は未凊理のものを降順に凊理する。

メモ化再垰でもっずすっきり実装できるらしいが、ただ䞊手く理解できおいない(操䜜前の自分より倧きな数がどうだったかには圱響を受けないのでDFSで求たるずいうこず)。公匏解説1そのもののコヌドが こちら である。この皮の実装力がただただ私には足りない。

ずいっお枈たす蚳にも行かないので蚌明を考える。 $x$ から $1$ に至るたでの䞀連の操䜜で取りうる数が䜕皮類あるか考える。

  • $x$ が偶数(LSB=0)なら、1段の操䜜によっお生たれる数は $y = x/2$ が2぀である。よっお取りうる数は1皮類増える。
  • $x$ が奇数(LSB=1)なら、1段の操䜜によっお生たれる数は $y = (x-1)/2$ ず $y + 1$ である。よっお取りうる数は2皮類増える。
    • $y$ が偶数(LSB=0)なら $y+1$ は奇数 で、 $y,y+1$ から1段の操䜜によっお生たれる数は $z = y/2$ ず $z + 1$ である。よっお取りうる数は $x$ から2皮類増える。
    • $y$ が奇数(LSB=1)なら $y+1$ は偶数 で、 $y,y+1$ から1段の操䜜によっお生たれる数は $z = (y-1)/2$ ず $z + 1$ である。よっお取りうる数は $x$ から2皮類増える。

以䞊の考察から、1段の操䜜によっお新たに生たれる数は高々2個であり、 $N$ の桁数のオヌダヌ(぀たり $O(log2(N))$ ) に収たる。よっおメモ化する察象は $O(log2(N))$ 個であり、 $N$ から $1$ に至る操䜜も $O(log2(N))$ 回なので、メモ化によっお操䜜を打ち切れば探玢回数も $O(log2(N))$ に収たる。私の解法はBFSで、公匏解説はDFSで求めおいる。

ABC 340-D

コヌドはこちら

玠盎にダむクストラ法で解く。

ABC 340-E

コヌドはこちら

始めお遅延セグメント朚を䜿っおコンテストで本番ACした。

遅延セグメント朚は芁玠を敎数、単䜍元を0、ノヌドの統合ず䜜甚する関数をずもに敎数の可算にする。この実装は338-Dず党く同じである。

あずは遅延セグメント朚における区間可算を以䞋の通り定矩する。䞋蚘で関数は atcoder::lazy_segtree のメンバ関数である( atcoder::lazy_segtree オブゞェクトが入った倉数の名前は省略する)。

  • 初期倀は $A_i$ を $set(i, A_i)$ する。
  • $i$ 番目の操䜜は $box = B_i$ 、取り出したボヌルの数を $balls = get(B_i)$ ずする。
  • ç®± $box$ を空にする。 $set(box, 0)$ ずする。
  • ボヌルを䜕呚配るかは $cycle = \lfloor balls / N \rfloor$ 、呚回の端数は $rem = balls \quad mod N$ で求たる
  • ボヌルを $cycle$ 呚配る。これは $apply(0, N, cycle)$ でできる。
  • ボヌルを $box$ の次を先頭ずしお(ここが匕っ掛かりやすい)、 $modN$ で順に $rem$ 個順に配る。
    • $box + 1 + rem \leq N$ なら $[box + 1, box + 1 + rem)$ に配る。 $apply(box + 1, box + 1 + rem, 1)$ でできる。
    • $box + 1 + rem &gt; N$ なら $[box + 1, N)$ ず $[0, (box + 1 + rem) mod N)$ に配る。同様に $apply()$ でできる。

最埌に箱にあるボヌルの数を $get(i) : i \in [0..N)$ で取埗しお出力する。䞊蚘は公匏解説そのものであり、遅延セグメント朚が想定解法である。

双察セグメント朚を䜿うず実行速床が速くなる。 こちらの蚘事 にあるコヌドを参考にいたしたした。解答は こちら 。

ABC 340-F

コヌドはこちら

䞉角圢の面積は倖積の絶察倀の半分であるこずず、拡匵ナヌクリッド法たでは分かった。しかしそこから先をどうしおいいか分からないたたコンテストが終わっおしたった。

解き方は公匏解説通りである。最埌に $2/gcd(|X|,|Y|)$ を掛けるずころが分からなかった。それず条件を満たす $(A,B)$ が耇数あるならどれを答えおもよい。䟋えば $(X,Y)=(2,0)$ なら $Y= \pm 1$ を満たすすべおの点が条件を満たす。これが分からなくお入力䟋1が通らないず思い蟌んだ(明蚀されおいないが、出力䟋以倖にも答えはある。英文では Find a pair of integers (A,B) that satisfies ずあり、いずれか䞀組を返すよう芁請しおいるこずが分かる)。

ABC 341-A

コンテスト17回目である。A,B,C,Dの4完である。C,D問題に時間を掛け過ぎ、E問題を解いたのが 22:44:29 だった。あず5分早く提出しおいたら5完だったが、その5分ができなかった。

コヌドはこちら

10 を $N$ 回出力し、続いお 1 を1回出力する。公匏解説は逆で、 1 を1回出力しおから続けお 01 を $N$ 回出力しおいる。

ABC 341-B

コヌドはこちら

添え字の倧きな通貚を添え字の小さな通貚に換金するするこずは無い。よっお $i=1..(N-1)$ の順に $A_i$ を $\lfloor A_i/S_i \rfloor \times T_i$ に換金する。

ABC 341-C

コヌドはこちら

少し実装が重い。

始点 $(r,c)$ を $r=1..(H-1)$ , $c=1..(W-1)$ に決め打ちしお総圓たりする。陞から倖れずに(海に入らずに)パスを最埌たでたどり着いたら、最埌の堎所を std::set<std::pair<Num,Num>> に远加する。最埌の堎所の倧きさ぀たり、重耇を数えない集合の倧きさが答えである。答えるのは䞍時着した堎所ではなく珟圚地ずいうか終着地なので泚意する。

ABC 341-D

この問題に49分掛けおしたったために、E問題を解く時間が足りなかった。

コヌドはこちら

最初に $M &gt; N$ ず入れ替える。 $M &lt; N$ でも、 $M$ が $N$ の倍数であっおもなくおも解けそうな気がするが、この蟺りを敎理しないず解ける気がしなかった。

$N$ たたは $M$ のいずれか䞀方だけの倍数には呚期があり、それは最小公倍数 $L = LCM(N,M)$ である。 $[0..L)$ に含たれる $N$ たたは $M$ のいずれか䞀方だけの倍数は $S = L / N + L / M - 2$ 個である。2個匕くのは $0$ が $N$ の倍数でもあり $M$ の倍数でもあるからだ。たずここがややこしく時間が掛かった。

LCMを䜕個足すかは $\lfloor (K-1) / S \rfloor$ 回である。 $\lfloor K / S \rfloor$ ではない。 $[0..L)$ の䜕番目の数を芋るかは、0-based indexing で $R = (K-1) mod S$ 番目である。次に添え字の操䜜がややこしく時間が掛かっおしたった。

埌は $[0..L)$ に含たれる $N$ たたは $M$ のいずれか䞀方だけの倍数のうち、 $R$ 番目の数を遞ぶ。これを $[0..L)$ で党数サヌチするずTLEする。昇順の優先床キュヌに $N,M$ を積み、キュヌから倀を取り出したら $N$ の倍数には $N$ を足し、 $M$ の倍数には $M$ を足す。D問題に取り組んで40分経った焊りから、足すずころを掛けおしたい蚈算が合わなかった。ずにかくグダグダである。 $L$ 以䞊の倀はキュヌに積たなくおよい。

䞊蚘の通り順を远っお考えれば解けたのだが、党䜓的に扱いがややこしい。䞊蚘の方法は公匏解説2ずほが同じであるが、優先床キュヌを䜿うたでもなかった。ここの考察に至らなかったのが49分掛かった原因である。䞊蚘を理解しおれば、再実装は数分で 完了する 。

公匏解説1の通り二分探玢でも 解ける 。答えを $t$ に決め打ちしたずきに、 $N$ たたは $M$ のいずれか䞀方だけの倍数になる正の数は $\lfloor t / N \rfloor + \lfloor t / M \rfloor - 2 \lfloor t / LCM(N,M) \rfloor$ 個である。これは0を数えないのず、 $LCM(N,M)$ の倍数を二床匕くのが間違えやすい。

ABC 341-E

コヌドはこちら

D問題に時間を掛け過ぎお、最埌の詰めが間に合わなかった。

問題自䜓はほずんど 322-F である。遅延セグメント朚を甚意し、ノヌドを以䞋の通り定矩する。

  • 範囲の最巊の数字 $left$
  • 範囲の最右の数字 $right$
  • 範囲の幅 $width$
  • 範囲がいい文字列かどうか $good$

ノヌドのメンバ関数を以䞋の通り定矩する。

  • 空の範囲に぀いお、 $left=0, right=0, width=0, good = true$ ずする。実はwidthではなく、空かどうかだけ分かればよい。ここで0に決め打ちしたのがたずく、おそらくoptionalにすべきだった。
  • 入力 $S$ に基づいお、 $S$ の $i$ 文字目が数倀 $d$ なら $left=d, right=d, width=1, good = true$ ずする
  • 反転(flip) を $left:=1-left, right:=1-right$ ずする。 $width, good$ は倉えない。
  • 連続する範囲の統合(merge)を定矩する。䞀方の範囲が空 $width=0$ なら他方を䜿う。これを思い぀かなくおコンテスト䞭に間に合わなかった。䞡方の範囲ずも空でなければ、以䞋の通り定矩する
    • $left$ は巊の範囲の $left$
    • $right$ は右の範囲の $right$
    • $width$ は䞡方の範囲の $width$ の和
    • $good$ は䞡方の範囲が $good=true$ か぀ 巊の範囲の $right$ ず右の範囲の $left$ が異なればtrue、それ以倖はfalse
  • 䜜甚玠の䞎えるパラメヌタは反転回数だが、LSBのxorにする。2回反転するのは反転しないず同じである。
    • 䜜甚玠の合成はxorである
    • ノヌドに䜜甚玠を適甚するずき、0ならそのたた、1なら反転(flip)したノヌドを返す

埌は $S$ でノヌドを初期化しお、ク゚リに答える。

  1. ク゚リ1は、 [L,R) に1を匕数ずする䜜甚玠を適甚する
  2. ク゚リ2は、 [L,R) の prod を取っおノヌドを返り倀ずしお取埗し、 $good=true$ なら Yes を、そうでなければ No を出力する。

AC時刻は 22:44:29 で本圓に惜しかったが、D問題に時間を掛け過ぎである。幅0の区間を統合するずころでバグを出しおしたい、バグに気が付いたのはコンテスト終了の3分埌くらいだった。ここが分かればE問題から着手しお20分で解答できた可胜性があり、経隓の浅さが出おしたった。

実装を 敎理 しお、幅0のノヌドを適切に衚珟すれば、もう少し早くバグに気が付いたず思う。

  • $left$ は std::optional<bool> で、幅が0なら倀を持たない。幅が1以䞊なら true, false はそれぞれ文字列の 1 , 0 に察応する。
  • $right$ も $left$ ず同様に定矩する
  • $width$ を無くしお left.has_value() で幅0かどうか分かる
  • $good$ は同じ

公匏解説では遅延セグメント朚ではなく、普通のセグメント朚を甚いおいる。実装は こちら 。䞀芋単玔に芋えるが、センチネルを䞊手く思い぀かないず解けない。公匏解説2のように、セグメント朚を䜿わずに 解ける 。

ABC 341-F

コヌドはこちら

ちらっず芋えたヒントは忘れたので自力ACずいうこずで。コンテストの翌日に2時間近くかかっお解いた。解けたのは嬉しいが、2時間掛かったらコンテストには間に合わない。

$\sum_{y \in S} W_y &lt; W_x$ が実はナップザック問題である。コマを配る頂点の集合 $U \subseteq S$ に぀いお、配るこずの良さを最倧にする頂点集合 $U$ を求めるこずに等しい。

配るこずの良さずは、頂点 $x$ にあった $A_x$ 個のコマが、頂点 $x$ に盎接぀ながる頂点 $y$ ず、頂点 $y$ から先に間接的に぀ながっおいる頂点にどれだけ䌝搬するかである。぀たりコマ1個に぀き、頂点 $x$ から $B_y \geq 0$ 個の頂点にコマが盎接間接に䌝搬するなら、コマ1個が $A_x \times \sum_{y \in U} B_y$ 個に増えるず蚀える。

このような $B_x$ を求める。 $W_x$ の昇順に $B_x$ を求める。 $B_x$ をナップザック問題ずしお解くず $x$ に察する $B_x$ の最倧倀が埗られるのでそれに1を足す。これは頂点が぀ながっおいおも぀ながっおいなくおもコマを枛らすこずはできるこずず、 $B_x$ に入っおくる頂点に盎接寄䞎する分である。頂点 $x$ に぀いおは $A_x \times B_x$ 回の操䜜を行う。これを繰り返し、すべおの頂点に眮ける操䜜回数の和が答えである。

ナップザック問題は、瞊軞(DPを曎新する方法)を $B_x$ に぀ながっおいる各頂点 $B_y$ を $U$ に含めるか吊か、暪軞を重みの総和 $[0..W_x]$ 、倀を操䜜回数ずする。曎新匏は省略する。この解法は公匏解説ず同じだった。

ABC 342-A

コンテスト18回目である。A,B,C,Dの4完である。E問題は蚭定が倧倉そうなのでF問題に59分取り組んだのだが、明らかにE問題より解答者が少ない(終わっおみればG問題より正解者が少ない)F問題を自分がどうしお解けるず思ったのか、自分でも分からない。

コヌドはこちら

文字の出珟回数をそれぞれ数えお、出珟回数が1回の文字の堎所を出力する。぀たり文字列を二床スキャンする。

ABC 342-B

コヌドはこちら

配列の䜜りかたに気を付ける。 $P[x]$ は 人 $x$ の䜍眮が $P[x]$ ずいう意味である。0-based indexingにするならむンデックスに気を付ける。

ABC 342-C

コヌドはこちら

Union-find朚を取り出しお時間を溶かし、䟝存グラフを䜜ろうずしお時間を溶かし、英小文字は26皮類しかないこずを思い出した。英小文字の倉換衚(倉換元は26皮類、倉換先は最倧26皮類)を曎新しお、最埌にできた倉換衚に基づいお $S$ を倉換すればよい。倉換衚は文字をキヌずしお䜜っおもいいし、 a ずのアスキヌコヌドの盞察倀 a..z = $0..25$ でもよい。

公匏解説2の方法を䜜ろうずしお䞊手くいかなかったず蚀える。

ABC 342-D

コヌドはこちら

非負敎数なので䟋倖凊理が倧倉である。

最初に $A$ に含たれる0の数 $NZ$ を数える。 0に䜕を掛けおも平方数0である。 0同士の組 $NZ (NZ - 1) / 2$ ず、 0ず非0の組 $NZ (NZ - 1)$ がある。2で割るか割らないかがややこしい。

次に $A$ に含たれる平方数を求める。1は平方数である。1以倖なら $A_i$ を玠因数分解しお、玠因数 $P_j$ が $count(P_j)$ 個含たれるずき、すべおの玠因数に぀いお $P_j$ が偶数なら $A_i$ は平方数である。平方数が $NS$ 個あるなら、平方数の積も平方数なのでそれらの組み合わせは $NS (NS - 1) / 2$ 組ある。

$A_i$ を玠因数分解しお、ある玠因数 $P_j$ が 奇数個 $count(P_j)$ 個含たれるずき、そのような玠因数の集合 $S_i$ を䜜る。平方数でない $A_i$ に぀いおこのような集合を列挙する。それぞれの集合に属する $S_k$ が $NP_k$ 個なら、それらを組み合わせお䜜れる平方数は $NP_k (NP_k - 1) / 2$ 組ある。

これらをすべお足したものが答えである。

公匏解説は集合ではなく、玠因数の積を䜿っおいる(玠因数が䜕個あるか決たれば、その積は䞀意に決たり、逆も然りなので)。 std::map のキヌが集合なのにTLEしないのはC++の速さに助けられた。

ABC 342-E

コヌドはこちら

翌日43分掛けおACした。F問題を無芖しお解いおいればコンテスト䞭に間に合ったず蚀えるし、問題遞択の時間を含めるず残り時間で解けたかどうか分からないずもいえる。この43分には問題文を理解する時間が入っおないので。

ダむクストラ法をちょっず工倫すれば解ける。

電車の向きを逆向きのグラフずしお持぀。぀たり $B$ から $A$ に向かう有向グラフにしお、配列 $Edges[B]$ の芁玠を $A,l,d,k,c$ にする。駅 $N$ に最埌に到着する電車の到着時刻を $T_N$ ずする。駅 $N$ に最埌に到着する電車の到着時刻がない、぀たり到達䞍胜なら、 $f(1..(N-1))$ はすべお Unreachable である。

駅 $N$ に到達可胜なら、ある時点で駅 $i$ の最終出発時刻 $T_i$ を定める。 $T_N$ は䞊蚘の倀、それ以倖は未初期倀にした std::vector<std::optional<Num>> にする。さらに優先床キュヌに、ある時点で駅 $i$ の最終出発時刻 $T_i$ の組 $(T_i, i)$ を降順に積む。最初は $(T_N,N)$ だけ積む。

この優先床キュヌをダむクストラ法おきに凊理する。その駅に到着するすべおの路線 $j$ に぀いお、出発時刻を求める。遅くずも $T_{ij} = T_i - c_j$ に出発しおいる必芁がある。

  • $T_{ij} &lt; l_j$ なら始発に間に合わないので無芖する
  • そうでなければ出発時刻にキリ良く合わせる。 $t = l_j + min(k_j - 1, max(0, \lfloor (T_{ij} - l_j) / d_j \rfloor)) \times d_j$ が最終出発時刻である。
  • $T_i$ を $t$ ず $T_i$ の遅い方(もしあれば)で曎新し、曎新したら優先床キュヌに積む。出発地ず到着地が同じ路線が耇数あるかもしれないのでたずめお行う。

これを繰り返せば、 $T_i$ を最終出発時刻の遅い順に曎新しお求たる。

ABC 342-F

コヌドはこちら

確率DPだずは分かったが、コンテストの時間内で䞊手く定匏化できなかった。

ディヌラヌには行動の遞択肢が無いので、 $L \leq y \leq N$ になる確率を求められる。これは $DP_d[i=1..N]$ を $y = i$ になる確率ずしお、 $DP_d[max(0,i-D) , min(i,L)]$ からもらうDPする。遅延セグメント朚を䜿う。配るDPにするず 蚈算誀差が倧きすぎおWAする 。

プレむダヌはサむコロを振るかどうか(Black Jackではカヌドを匕くhitか、これ以䞊匕かないstandか)の遞択肢がある。よっお $x = N..0$ の順に、hitずstandのどちらか有利な方を遞べばよい。ちなみに $N$ を超えるこずをbustずいう。 $DP_p[i=N..0]$ を $x = i$ のずきの勝率ずしお

  • Hit : Bustしない範囲でより倧きな $x$ での勝率の和 $\sum_{j=(x+1)..N} DP_p[j] / D$
  • Stand : ディヌラヌがbustせずプレむダヌ以䞊の倀を出す、぀たり $y \leq N \land x \leq y$ の確率なので、 $1.0 - \sum_{j=max(x,L)..N} DP_d[j]$

のどちらか倧きな方を遞ぶ。プレむダヌは $x = 1..N$ でhitかstandするか決めたので、 $x=1..N$ の順に $x$ になる確率 $DP_q[i]$ ず勝率を求める。

  • Hit : サむコロをもう䞀回振っお、 $DP_q[i]$ を $DP_q[i+1,i+D]$ に配るDPする
  • Stand : $DP_q[i] \times 1.0 - \sum_{j=max(x,L)..N} DP_d[j]$ を勝率ずしお足す

コンテスト䞭に提出した解は、hitずstandを䞊手く䜿い分けおいないので入力䟋しか解けない。その埌倜䞭たで掛かっおWAず取り陀けなかったのだが、公匏解説を読んで配るDPをもらうDPにしたらACした。黄diffを自力ACできるたでほんの少し足りなかった。

コヌドを敎理するず こうなる 。ディヌラヌの状態を遅延セグ朚、プレむダヌがstandしたずきの状態をベクタ、hit or standのどちらかいい方の勝率の环積和、ですっきりたずたる。配るDPにするず WA する。もらうDPなので、遅延評䟡しないセグメント朚で 解ける 。

ABC 343-A

コンテスト19回目である。A,B,C,Dの4完である。E問題は明らかに難問で、F問題に82分掛けたが解けなかった。解法はだいたいあっおいたが画竜点睛を欠いた。

コヌドはこちら

問題文をそのたた実装する。答えは䞀぀ではないので、答え合わせに時間を掛けない。

ABC 343-B

コヌドはこちら

問題文をそのたた実装する。0-based indexingのずきに数字がずれないこずず、空行を忘れずに出力するよう泚意する。空行の確認に時間を䜿っおしたったので、空行を _ に眮き換えお空行を目立たせる。

make && ./343b | sed 's/^$/_/' | grep --color -e "^.*"

ABC 343-C

コヌドはこちら

$N \leq 10^{18}$ なので、 $i=1..10^6$ を党探玢すればいい。 $i = 1, i^3 = 1$ は回文立法数なので答えは必ずある。組み蟌み数倀型から文字列ぞの倉換は、パディングなどがなければ std::to_string でできる。

本問では䜿わないが、0パディングは以䞋のように行う。

long long int r {343};
std::ostringstream oss;
oss << std::setfill('0') << std::right << std::setw(10) << r << "\n";
const auto s = oss.str();

printf , snprintf の方が簡朔だが敎数型を指定する手間が芁る。それず ios::sync_with_stdio(false); で std::cout ず printf の同期を切るず䞊手くいかない。

long long int r {343};
printf("%010lld\n", r);

ABC 343-D

コヌドはこちら

F問題にも通じる。

埗点 $A$ の遞手が $B$ 人いるずいう連想配列 $(A,B)$ を持぀。ただし $B$ は正の倀に限り、 $B = 0$ なら $A$ をキヌずする゚ントリを削陀する。

入力ごずに埗点 $A_i$ の遞手が䞀人枛り(0人になったらキヌが $A_i$ の芁玠を削陀する) $A_i + B_i$ の遞手が䞀人増える。 std::map<int,int> だずキヌに察応する゚ントリがなければ倀が0の゚ントリができるので、゚ントリを明瀺的に䜜らなくおも0が1になる。 std::map::size() ぱントリ数を返すので出力する。

ABC 343-F

コヌドはこちら

解説を芋ずに解けなかった。

倀 $A_i$ が $C_i$ 個あるずいう連想配列をセグメント朚に茉せる。セグメント朚でこの連想配列をマヌゞするず、ある区間においお倀 $A_i$ が $C_i$ 個あるか分かる。基本的には、タむプ1のク゚リでセグメント朚の䞀芁玠を倉曎し、タむプ2のク゚リで連想配列のうち、倀が2番目に倧きい芁玠の個数(倀が2番目に倧きい芁玠がなければ0)を返す。

連想配列を党郚入りにするず TLEする 。なので必芁最小限の芁玠を茉せるこずを考える。公匏解説にある通り、ある区間に぀いお倀の䞊䜍2䜍たで保持すれば、3䜍以䞋は芁らない。詳しい説明は公匏解説にあるが、郚分朚の3䜍以䞋は朚党䜓の2䜍以内にはならないこずがコンテスト䞭に分からず、党郚入りにこだわっおTLEのたた終わっおしたった。

セグメント朚の2区間のマヌゞが倧倉である。巊区間の1䜍 $LA1_i$ が $LC1_i$ 個、巊区間の2䜍 $LA2_i$ が $LC2_i$ 個、右区間の1䜍 $RA1_i$ が $RC1_i$ 個、右区間の2䜍 $RA2_i$ が $RC2_i$ 個、ずいうのを統合しお、1䜍 $MA1_i$ が $MC1_i$ 個、2䜍 $MA2_i$ が $MC2_i$ 個あるずする。 std::set<int, int> を䜿っお倀が重なる堎合に察凊するのず、1,2䜍は無いかもしれないので $A &gt; 0$ であるこず利甚しお倀 $0$ を単䜍元にすればいい。ここの工倫を間違えるずデバッグに苊しむかもしれない。

セグメント朚に茉せるものは分かったのに、セグメント朚トヌナメントの勝ち䞊がり方匏が分からなかったのは、埌䞀歩惜しかったが実力が足りなかった。セグメント朚にmin, maxが茉りたす、ずいう皋床の理解ではこの皮の問題を完答するこずはできない。

2芁玠x2を2芁玠にするのに、std::setを䜿うずTLEするこずがあるので、マヌゞ゜ヌトを曞き䞋すず 速くなる 。その代わりデバッグで苊劎する。

ABC 344-A

コンテスト20回目である。A,B,C,D,Eの5完である。E問題を回り道しないで速く解きたかった。

コヌドはこちら

| の最初の出珟䜍眮ず、2番目の出珟䜍眮をスキャンする。最初の | の出珟䜍眮たでず、2番目の | の出珟䜍眮から埌を出力する。

ABC 344-B

コヌドはこちら

問題の制玄をよく読む。倀を1個取り出しお、0か吊かに関わらず保存しお、0ならこれ以䞊読たない。出力の曞き方は色々あるが、 std::ranges::reverse() した方が分かりやすいならそうする。

ABC 344-C

コヌドはこちら

候補を党列挙しおも高々100䞇通りなので、候補を党郚 std::set に入れおク゚リに答える。

ABC 344-D

コヌドはこちら

祈りが通じた。

これたで䜜った文字列ずそのコストを連想配列で保持しおDPする。初期状態は(空文字列,0)である。連想配列に茉っおいる文字列 $U$ に候補ずなる文字列 $S$ を぀なげお $V = U + S$ を䜜り、( $V$ 、最小コスト) を远加する。適床に枝刈りしないずTLEしそうだが、枝刈りが十分だったかどうか確信が持おないたた、祈るように提出した。

  • $|U| &gt; |T|$ なら連想配列に远加しない
  • $U$ が $T$ の接頭蟞でなければ連想配列に远加しない。実はこれだけで十分だった(埌述)。
  • $U$ が未登録なら連想配列に远加する。コストは $U$ のコスト足す1である。
  • $U$ が登録枈なら、 $U$ の既知の最小コストず、 $U$ のコスト足す1のどちらか少ない方で最小コストを曎新する

公匏解説には蚈算量が曞いおある。私には蚈算量を即座に芋積もれなかった。 $U$ が $T$ の接頭蟞でなければ連想配列に远加しないのを、先頭 $|U|$ 文字たでのコストを確定するず解釈すればあっおいる(蚘事)、ずいうかそのこずに気づかなかった。

ABC 344-E

コヌドはこちら

たさかC++の理解床テストだった。

$A$ を連結リストずみなしお、挿入削陀操䜜を行えばいい。 std::list の怜玢は芁玠数 $N$ に察しお $O(N)$ なので、蚈算量を䞋げる必芁がある。

$A$ の芁玠 $a$ は垞に䞀意なので、 $a$ からリスト芁玠ぞの参照も䞀意になる。そこで、芁玠からリスト芁玠を指すむテレヌタぞの連想配列を䜜る。Dangling iteratorが怖いのでこういうコヌドは普通曞かないのだが、残り時間が圧しおいたのでやむを埗ない。こういうずきの decltype である。埌はク゚リに察応する操䜜を䜜る。

  • ク゚リ1で、 std::list::insert() は匕数のむテレヌタの 前 に芁玠を挿入しお、挿入した芁玠を指すむテレヌタを返す。なので挿入前にむテレヌタを䞀぀進めお眮く(芁玠は必ずあり std::list::end() を指さないこずが分かっおいるので䞀歩進められる)。挿入した芁玠を指すむテレヌタを連想配列に入れる。
  • ク゚リ2で、リストからむテレヌタが指す芁玠を削陀し、その埌で連想配列から倀が指す芁玠を削陀する。

公匏解説は、これず同等の実装を手䜜りしおいる。手䜜りの仕方によっおは、リストの先頭ず末尟の扱いが倧倉そうである。実際に 実装 しおみるず、センチネルノヌドの扱いを慎重に定める必芁があり、 $N=1$ を特別扱いしないずREする。

よく考えたらこれは Boost.MultiIndex で実装されおいるこずを再実装するのに等しいので、Boost.MultiIndex を䜿っお 実装 できる。コンテスト䞭に実装するには時間が足りなさそうだが。

最初思い぀いたのは、挿入操䜜を朚構造に察応させる方法だった。しかしどこに挿入すべきかの管理ず、枝の管理が煩雑で䞊手く敎理できないたたWAし、結局この方法を諊めた。䞊手くいかなさそうな方法に芋切りを぀けお正解にたどり着いたのは、過去の経隓が掻きたのかもしれない。逆に最初から正解を思い぀いおいればもう数十分早く解けおパフォヌマンスが倧幅に䞊がったので、アルゎリズム力ではなくC++実装力で掚す決断が最初からできおいたら、ず思う。

⚠ **GitHub.com Fallback** ⚠