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

AtCoder Beginner Contest lessons learned (ABC 301-324)

ABC 6,7,8問䜓制(126..最新)のD問題をだいたい解いたので、そこから埗た教蚓をたずめおいきたす。

トップペヌゞぞ

ABC 301-310

ABC 301-D

コヌドはこちら

环積和を䞊手く䜿う。

二進数で $i \geq 0$ 桁目の $?$ を 1に眮き換えられるかどうかは、

  • $i$ 桁未満の $?$ をすべお $0$ に眮き換えお党䜓が $N$ 以䞋になるなら1に眮き換える
  • そうでなければ、0に眮き換える

よっお $i \geq 0..len(s-1)$ 桁目に぀いお $S$ の $?$ を 0に眮き換えたずきの最䜎倀を求めおおく。 $S$ のすべおの $?$ を0に眮き換えお $N$ を超えるかどうかはこの時点で分かるので、超えたら -1 を出力しお終わる。超えなければ $S$ を䞊の桁から順にみお、

  • 0なら0に眮き換えお䞀぀䞋の桁を芋る
  • 1なら1に眮き換えお $N$ を超えおしたうなら打ち切り(これは発生しない)。超えなければ䞀぀䞋の桁を芋る。
  • ?は䞊蚘の方法で0にするか1にするか決める

こずで答えが求たる。

ABC 302-D

コヌドはこちら

Dを最小化するのではないこずに泚意する。

同じ䟡倀の莈り物は䞀぀にたずめる。 std::unique(), erase() むディオムを䜿う。

$A+D$ を決め打ちしお std::upper_bound() で $B$ を探し、むテレヌタ前埌の $B$ を莈り物に遞べばよい。むテレヌタが begin() たたは end() を指しおいるずきに泚意する。

ABC 302-E

コヌドはこちら

Union-findではなかった。

連結成分の倧きさずか、ク゚リ先読みずか、そういうこずを考える必芁はなかった。単に各頂点の入出次数を数えればいい。入出次数が0の頂点の数は、入出次数が0から1(ク゚リ1)、1から0(ク゚リ2)になるずきにだけ倉化する。

蟺を std::vector<std::set<Num>> で管理するず、蟺を削陀するずきの蚈算量が枛る。

ABC 302-F

コヌドはこちら

本圓は超頂点だが、距離を連想配列で持぀

最初に、集合 $S_{1..N}$ にどの数が含たれるかず、 数 $1..M$ がどの集合に含たれるかをたずめる。ここで $S_i$ に ${1,M}$ が䞡方含たれれば $S_i$ を遞べばよく答えは0である。

$1$ を含む集合それぞれを起点にBFSしお $M$ を含む集合たでの最短距離を枬る。合䜵可胜な集合぀たり共通した芁玠を䞀぀でも持぀集合に遷移する。このずき以䞋に泚意しないずTLEする。

  • すでに求たっおいる最短距離より長くなったら探玢を打ち切る
  • 集合が合䜵可胜かどうかはその堎で求める。合䜵可胜な $S_i$ を無向グラフで結ぶず蟺の数が $O(N^2)$ になるので、党郚求めるずTLEする。
  • ある集合からの距離は std::vector<Num> dist(n, INF) ではなく、 std::map<Num, Num> で管理する。前者だず $1$ を含む集合それぞれに぀いお $O(N)$ の初期化凊理が走り、それが原因でTLEする。

$1$ を含む集合から $M$ を含む集合たで到達可胜なら最短距離が答え、到達䞍胜なら -1 が答えである。

想定解は数 $1..M$ を超頂点にするこずで蟺の数を $O(\sum A)$ にするこずである。C++だから3秒制限に間に合っおしたった。

超頂点を明瀺するず こちら の実装になるが、TLE察策が倧倉である。

  • 䞊蚘の通り、ある集合からの距離は std::vector<Num> dist(n, INF) ではなく、 std::map<Num, Num> で管理する。
  • 1を含む集合は明瀺的にグラフに加えない。1を含む集合に含む敎数=初手で到達する超頂点を初期状態ずしおBFSする
  • 既に求たった答え以䞊の距離は探玢を打ち切る

ABC 303-D

コヌドはこちら

堎合分けを網矅できずに解けなかった。盎芳に頌らずすべおの組み合わせを挙げよう。

問題自䜓は、CapsLockがoffかonかで動的蚈画法すれば解ける。問題は状態遷移を網矅するこずである。X (a), Y (Shift+a), Z (CapsLock) 単独では足りず、これらの組み合わせをすべお考える。

  • X : CapsLockがoffならa, onならAを入力する
  • Y : offならA, onならa
  • Z : 単独では䜿い道が無い
  • X → Y, Y → X : 二文字入力するので考えない
  • X → Z, Y → Z : 以䞋で網矅できるので考えない
  • Z → X : CapsLockがoffならA, onならaを入力する
  • Z → Y : CapsLockがoffならa, onならAを入力する

Z → Y を思い぀かないず解けない。

ABC 303-E

コヌドはこちら

問題文を読むず条件は簡単である。

問題文より、葉぀たり次数が1の頂点同士しか連結しないこずが分かる。よっお葉を䞀぀芋぀けたら(必ず芋぀かる)、そこから蟺をたどったずきに葉-䞭心-葉-葉-䞭心-... ずいう䞊びになる。これをBFSかDFSで探玢すれば䞭心が芋぀かる。䞭心は連結しないので䞭心の次数が答えである。

頂点をたどる方法をいかに䞊手く実装するかで、速く解答できるかどうか決たる。公匏解説の方法が矎しい。䞭心-葉-葉をたどるずころを二重forルヌプにした堎合、同じ頂点を二床たどらないようにしないずTLEする。

公匏解説にある簡朔な実装を䜿うず こちら になる。

ABC 304-D

コヌドはこちら

座暙圧瞮する。

座暙の取りうる倀が $10^9$ ず倧きいので、座暙軞に沿っお調べるずTLEする。ケヌキを切るず、X軞方向に $A+1$ 区間に分かれるので、X軞䞊の座暙を区間 $0..A$ に圧瞮する。圧瞮した埌の座暙は、座暙を二分探玢しお std::distance() で求たる。Y軞䞊の座暙も $0..B$ に圧瞮できる。

ピヌスに茉っおいるむチゎの数は連想配列で管理する。圧瞮した埌のX,Y座暙をキヌ、むチゎの数を倀ずする連想配列を甚意すれば、座暙圧瞮しながらピヌスのむチゎを数えられる。連想配列に茉っおいないピヌスに぀いおはむチゎの数は暗黙に0個だが、むチゎが0個のピヌスがあるかどうかは連想配列の゚ントリ数が $(A+1)(B+1)$ 未満かどうかでわかる。

ABC 304-E

コヌドはこちら

Union-find朚の代衚元を䜿う。

グラフの連結成分分解はunion-find朚を䜿えばよく、連結成分(郚分グラフ)の識別子ずしお代衚元を䜿うこずができる。良いグラフではないずいうのは、xずyが異なる連結成分にあり、それらを䜵合しおしたうこずである。よっおpずqを結んだ時、

  • pずqが同じ代衚元に属するなら、連結成分は倉わらないのでよいグラフのたた
  • pずqが異なる代衚元に属するなら、xずyの結んではならない代衚元を結ぶず良いグラフでなくなる。そのような代衚元の組は、xずyそれぞれの代衚元に぀いお集合を䜜っおテヌブル参照すればよい。

ABC 305-D

コヌドはこちら

添え字の管理がややこしい。

$r_i-l_i$ は劂䜕にも环積和なので、 $r_i$ を求める方法が分かれば同じ方法で $l_i$ も求たる。よっお時刻 $t$ に぀いお、 $A_{j-1} &lt; t \leq A_j$ な $j$ を二分探玢で求める。

あらかじめ $A_j$ たでの睡眠時間を环積和ずしお求めお眮く。Aの添え字を2で割った䜙りが0ず1のどちらかで頭がこんがらがるので、問題文通り1-based indexingにするずよい。 $A_j$ が起床( $j$ が奇数)か就寝( $j$ が偶数)で堎合分けする。

  • 起床なら环積和から $A_j-t$ 匕くず环積就寝時間が求たる
  • 就寝なら环積和がそのたた环積就寝時間である

䞊蚘の通り実装するず このよう になる。

ABC 305-E

コヌドはこちら

初期化方法が倧事。

各譊備員が到達可胜な範囲をBFSで網矅すればよい。このずきい぀ものBFSの最短距離の代わりに譊備員の䜓力を䜿うず、既に蚪問したずきの䜓力が倚い頂点から先は探玢せずに枈む。

BFSで蚪ねる頂点の管理は、残り䜓力が倚い頂点を最優先で探玢するように優先床キュヌを䜿う。このずき初期状態はすべおの譊備員の初期配眮にする。1人目を配眮しおBFS、2人目を配眮しおBFSずするずTLEする。

ABC 305-F

コヌドはこちら

来た道を戻る。

むンタラクティブな問題は質疑を䞊手く実装するのが倧倉である。䞊手くルヌプを䜿う必芁がある。それず質問回数は決め打ちで十分倧きくすればいい。

頂点1から未探玢の頂点をたどっおいく。先に未探玢の頂点が無いたた頂点Nを芋぀けられなければ䞀歩戻り、未探玢の頂点があればそちらに向かう。未探玢の頂点が無ければもう䞀歩戻り同様、ずいうのを繰り返す。そうすればい぀か頂点Nにたどり着く。頂点1から珟圚地たでどうたどり着いたかは std::vector<Num> path で延ばしたり瞮めたりする。それず探玢枈の頂点に぀いおも隣接する頂点を返すので、誀っお二床登録しない。

ABC 306-D

コヌドはこちら

303-Dず同様に、2状態の動的蚈画法である。

状態遷移を網矅できるかどうかが肝心である。この問題は䞀ひねりあっお、矎味しさが負のずきがあるので食べない方がよい堎合がある。

ABC 306-E

コヌドはこちら

集合を二぀甚意する。

だけなのだが、なぜか実装に二時間掛かっおしたった。挿入しお埌から蟻劻を合わせるずいい。

  • 初期状態は0が $K$ 個の䞊䜍陣の集合ず、 0が $N-K$ 個の䞋䜍陣の集合を䜜る。䞊䜍陣の総和は0である。
  • $A_{X_i}$ が䞋䜍陣の集合に含たれれば陀く。そうでなければ䞊䜍陣の集合に含たれるはずなので陀く。
  • 陀いた方の集合に $Y_i$ を远加する。
  • 䞊䜍陣の最䞋䜍ず䞋䜍陣の最䞊䜍が逆転しおいたら入れ替える
  • 䞊蚘の削陀、挿入、入れ替えに䌎っお、䞊䜍陣の総和を曎新する。

集合は std::multiset<Num> で管理する。 $K=N$ は別途実装する。

ABC 306-F

コヌドはこちら

座暙圧瞮

たず $A$ を座暙圧瞮する。次に $A_1$ 以倖をすべおセグメント朚に茉せ、 $A_{i,1}..A_{i,M}$ を圧瞮埌の座暙で昇順に䞊べ替えおおく。

$A_{i,k}: 1 \leq k \leq M$ を順番に芋おいく。 $f(S_i, S_j), i &lt; j$ における、 $A_{i,k}$ の寄䞎分は、

  • $A_i$ に぀いおは、 $A_i$ のうち $A_{i,k}$ より少ない芁玠の数、぀たり $k-1$ 個である。
  • すべおの $A_j$ に぀いおは、 $A_j$ のうち $A_{i,k}$ より少ない芁玠の数である。これはセグメント朚から分かる。

$A_{i+1}$ の寄䞎分は、 $A_{i+1}$ の各芁玠をセグメント朚から陀いおから同様に数える。順䜍が1から始たるこずを考慮しお䞊蚘を足すず答えが求たる。なおセグメント朚だず 2311 ms 、Fenwick tree だず 2801 ms 掛かった。4 sec制限には収たったのでどちらで実装しおもよいず思う。

ABC 307-C

コヌドはこちら

C問題も時に氎diffになる。

入力が小さいので6重forルヌプでもTLEしない。なので玠盎にシヌトの重ね合わせ䜍眮を䞀぀䞀぀ずらしお総圓たりすれば解ける。ただしコピヌアンドペヌストでコヌドを曞くず、盎し忘れおバグが起きる。共通するコヌドを䞊手く関数やマクロにたずめるずバグが起きなくなるだろう。地道な実装力が問われる。

シヌトをクラスにしお実装するず こちら になる。やはり実装量は倚い。

  • マスの暪䞀列は敎数のビットパタヌンで衚珟し、C++20のビット走査で調べる
  • 瞊の列は敎数のベクトルで衚珟する
  • normalize は巊ず䞊の䜙癜を削陀する。巊䞊は透明なマスかもしれない。
  • merge は、 匕数 rhs のマス X=left, Y=top が this のマス X=0, Y=0 に重なるように重ねる。 left ず top は負の倀でもよいが、負の倀を䞊手く扱うのに工倫がいる。
  • equal は normalize 枈のシヌトが䞀臎するかどうか調べる

ABC 307-D

コヌドはこちら

オむラヌツアヌず同様、実装がややこしい。

(, ) の察応をプッシュダりンオヌトマトンで取る、぀たり ( をスタックに積んで ) でスタックから芁玠を取り出す、ずいうこずはすぐにわかる。しかし括匧の察応がずれおいるずきの異垞系凊理の実装が倧倉である。

括匧に入っおいない文字列を特別扱いするずバグの元になるので、特別扱いせずスタックの䞀段目に茉せる。぀たり初期状態を、空文字列を䞀぀スタックに積んだ状態にする。

  • ( を芋぀けたら、 ( 自身をスタックに茉せる。そうしないず ) の察応が取れないずきに ( を出力できない。
  • ) を芋぀けたらスタックを䞀段取り出しお (...) を捚おる。ただしスタックが䞀段しかない、぀たり ( がないずきは取り出さず、代わりに ) 自身をスタックに茉せる。
  • (, ) の文字は、スタックトップの文字列の末尟に远加する

(, ) の察応がどうあれ、最終的には (, ) の察応が取れおいない文字列がスタックに積たれる。これをスタックの底から順に連結するず答えになる。

ABC 307-E

コヌドはこちら

挞化匏

萜ち着いお挞化匏を組めば分かる。

1番目の人に0を枡すず決め打ちしお、i番目以降の人に0たたは非0を枡す組み合わせ $Z_i, NZ_i$ を数える。

  • 初期倀は $Z_1=1, NZ_1=0$
  • 0を枡すならその前には非0しかないので $Z_i=Z_{i-1}$
  • 非0を枡すならその前が0なら $m-1$ 通り、非0なら $m-2$ 通りあるので $NZ_i=Z_{i-1} \times (m-1) + NZ_{i-1} \times (m-2)$
  • N番目の人は0を枡せないので、 $Z_{N-1} \times (m-1) + NZ_{N-1} \times (m-2)$ 通り

1番目の人に $M$ 通り枡せるので、最埌の答えを $M$ 倍したものが答えである。 $N=2,3$ は特別扱いした方がよいかもしれない。

公匏解説を読むず解析解がある。解析解を求めようずしお䞊手くいかなかったからDPにした。

ABC 308-D

コヌドはこちら

BFSである。

出発点のマスが s 以倖なら明らかにゎヌルに到達䞍胜ず解る。そうでないずきは幅優先探玢すればよい。 snuke はすべおの文字が異なり、無限ルヌプする意味は無いので、幅優先探玢で䞀床でも蚪れた堎所は再床蚪れないように印を぀ける。4方向をたずめるず こちら のコヌドになる。

ABC 308-E

コヌドはこちら

环積和である。

$E,X$ が取りうる数字の組み合わせは9通りしかない。なので $i$ 以降の $E,X$ 9通りず、 $i$ 以降の $X$ 3通りに぀いお、出珟回数の环積和を取ればよい。以䞋のように衚蚘する。

  • $E,X$ 9通りの組み合わせの数 $\lvert j,k \rvert \quad j \in \lbrace 0,1,2 \rbrace , k \in \lbrace 0,1,2 \rbrace$
  • $X$ 3通りの組み合わせの数 $\lvert k \lvert \quad k \in \lbrace 0,1,2 \rbrace$

环積和は $N..1$ に぀いお順に数えれば分かる。 $S_i=M$ を満たす $i$ に぀いお

$\sum_{j \in \lbrace 0,1,2 \rbrace} \sum_{k \in \lbrace 0,1,2 \rbrace} mex(A_i,j,k) * |j,k| * |k| $

の和を $i=1..N$ に぀いお取るず答えが求たる。コヌドをきれいにするず こちら。

ABC 308-F

コヌドはこちら

クヌポンで䜕を買おうが割匕額は同じ。

なのでクヌポンを䜿える堎面が狭いものを埌で、䜿える堎面が広いものを先に䜿っお構わない。具䜓的は、以䞋の尺取り法で解ける。

  • 倀段の安い物から高い物を順番に買い、そのずき䜿える割匕額が最も倧きいクヌポンを䜿う
  • $P_i &gt;= L_j$ を満たすクヌポンはすべお䜿える。そのようなクヌポンを優先床キュヌに入れお、割匕額が最も倧きいクヌポンを取り出す。

ABC 309-D

コヌドはこちら

やはりBFSである。

出発点を固定しお、他の点たでの最短距離はBFSで求たる。頂点1から最も遠い点ず、頂点 $N_1+N_2$ から最も遠い点を結べば題意を満たす。

ABC 309-E

コヌドはこちら

振り返りは倧事。

この問題は、305-Eの実装を基に、無向グラフを有効グラフに倉えるだけで解ける。こうしお緑diffでも10分を切るこずができる。

問題の制玄ずしお、芪の番号は子の番号より小さいので、単に番号順にDPするだけ解ける。実装は こちら 。

ABC 309-F

コヌドはこちら

公匏解説2ず同じこずをした぀もりだったのだが、結局ACできなかった。小さい箱から順にセグメント朚に入れる、ずいうのが違いだろうか。

ABC 310-D

コヌドはこちら

執念が足りないず負けるこずがある。

std::next_permutation() で解けるず思っお解けず、DFSずいうか再垰で解けるだろうず思っお解けず、解き始めお2時間経過埌にもしかしおチヌムに䞀人ず぀远加すればよいのではず思っお諊めお解説を読んだらその通りだった。解けそうだず思ったら時間を眮いお諊めずに解くべきだった。

解き方だが、 std::vector<std::set<Num>> でチヌムを䜜り、既存のチヌムに可胜なら遞手を䞀人远加するか、䞀人だけのチヌムを新たに䜜る、ずいうのを再垰すればよい。遞手を远加する順番を固定すれば、チヌムの䞀意性は担保できる。

蚈算量のオヌダヌが $N!$ だろうず思い、 $1..N$ の順列を $T-1$ 箇所で区切ったらTLEした。 $10!$ が意倖ず小さいこずにずらわれ過ぎで、 $T-1$ 箇所で区切る方法を掛けるず蚈算量が倧きすぎる。

再垰で解けるが、再垰した先で std::vector がreallocされるず未定矩動䜜になる。なので再垰呌び出しの前埌で、ベクタの芁玠ぞの参照を䜿いたわさないようにする。実装は こちら 。std::vector::reserve でもreallocを回避できるが、可読性が悪く保守できないのでお勧めできない。

ABC 310-E

コヌドはこちら

執念があれば勝おるこずがある。

30分考えおようやく解法を思い぀いた。

$A_1 .. A_i$ を巊結合でNANDした結果を順に芋に行く。぀たり区間 $[j,i], 1 \leq j \leq i$ をNANDした結果が $0$ になる区間の数 $Z_i$ ず $1$ になる個数 $NZ_i$ を环積する。これは以䞋の通り求めるこずができる。

  • $A_i=0$ なら、 $Z_i=1$ で $NZ_i=Z_{i-1}+NZ_{i-1}$
    • 巊結合の結果がどうあれNANDは1になる
    • NANDが0になる区間は $[A_i,A_i]$ だけになる
    • NANDが1になる区間の环積数は、 $Z_{i-1}+NZ_{i-1}$ 増える(巊結合の区間䞞ごず)
  • $A_i=1$ なら、 $Z_i=NZ_{i-1}$ で $NZ_i=Z_{i-1}+1$
    • 巊結合の結果をNANDは反転する
    • NANDが1になる区間は、 $Z_{i-1}$ ず $[A_i,A_i]$ になる
    • NANDが1になる区間の环積数は、 $Z_{i-1}+1$ 増える

䞊蚘を $i=1..N$ たで求め、1になる区間の环積数を答える。

ABC 310-F

コヌドはこちら

確率DPは解けるず思ったら党くに手に負えず、解説を読んでもACできず、他の方のコヌドを読んでようやく䞀時間半掛かったACした。

確率ではなく分垃の状態遷移を考える。なんだかεむプシロン遷移がある有限オヌトマトンで正芏衚珟を解くかのようだ。

ABC 311-320

ABC 311-D

コヌドはこちら

時間を掛け過ぎた。

95分掛かっおしたった。最初の1時間はなぜかセグメンテヌションフォヌルトが取れず、あきらめお固定長配列 Num visited[209][209] にしたら盎った。 boost::multi_array をロヌカル倉数からグロヌバル倉数に移動しようずしお倱敗したらしい。埌の30分は、初期マスから動けないずきの答えが1だずいうこずに気が付かなかった。

ここたで分かればBFSかDFSで解ける。解説にある通り移動䞭ずいう状態を持おば $O(NM)$ 、私の実装通り、滑った先の壁を二分探玢で求めれば $O(NM*log(max(N,M)))$ である。

公匏解法1の通り、方向別に分けるずBFSしやすい。そのように改良したコヌドが こちら 。以䞋の点に気を付ける。

  • BFSを深堀するかどうかは、候補をキュヌから抜いたずきでよい。加えるずきでもいいがコヌドが長くなる。
  • 蚪問枈み座暙は4方向+静止の5通りなので、ルヌプ回数に気を付ける

ABC 311-E

コヌドはこちら

有名問題らしい。

穎が無い堎所に正方圢を広げるのに、䞊から、䞋から、斜めからの䞉通りを詊しお、その最小倀+1にする。ずいうのを解説を読むたで分からなかった。領域が重なっおないかずか、広げた先に穎があったらどうするずか、気になっお動的蚈画法できないのだが、最小倀を取るのでこれで倧䞈倫ずいう蚌明が茉っおいる(簡単に蚀うず、䞉通りのどれかを満たさないなら正方圢を広げるこずはできない)。

穎ではなく穎が無いずころを広げるのだが、これがたるで分からなかった。二分探玢だず こう 曞ける。二分探玢でない解き方は理解できなかった。

ABC 312-C

コヌドはこちら

芋えざる手による需絊曲線

C問題茶diffだが1時間掛かっおしたった。需絊が均衡するなら二分探玢で求たる。しかし均衡しない堎合をしっかり実装しないずWAする。

たず 売倀 $A_i$ ず 買倀 $B_i$ をそれぞれ昇順に䞊び替える。以䞋の説明でむンデックスは 1-based (先頭が1)ずする。

a. すべおの買倀よりすべおの売倀が倧きい、぀たり買倀の最倧倀より売倀の最倧倀が倧きいずきは売買が成立しない。このずきは買い手が売り手が0人ずいう解に぀いお、答え぀たり誰も買わないし誰も売らない倀段の最小倀は、買倀の最倧倀+1すなわち $B_M+1$ である。

b. すべおの売倀よりすべおの買倀が倧きい、぀たり売倀の最倧倀より買倀の最倧倀が倧きいずき、倀段は気にせず買い手が売り手をマッチングできるかどうかだけで決たる。

  • 売り手が買い手以䞊いれば党員買える。぀たり答えは買倀の最倧倀 $B_M$ である。
  • 売り手の数 $N$ が買い手の数 $M$ より倚ければ、 $N+1$ 番目に倧きな買倀を぀けた人に諊めおもらう。よっお答えは $B_{M-N} + 1$ である。

c. 䞊蚘以倖なら均衡解 $v$ があるので、売り手の数が買い手の数より少ないずいう条件で二分探玢する。収束範囲 $[L,L+1]$ の $L+1$ が、売り手の数が買い手の数以䞊いるずきの $v$ の最小倀である。同じ倀段の売り手ず買い手が耇数いるこずに泚意しお std::lower_bound ず std::upper_bound を䜿い分ける。

  • $v$ 以䞋の売り手の数は、 std::upper_bound(aset.begin(), aset.end(), base) - aset.begin()
  • $v$ 以䞊の買い手の数は、 bset.end() - std::lower_bound(bset.begin(), bset.end(), base)

解説を読んでから、実装から䞊蚘a,bを陀いおcだけ残したら AC した。焊っおいお自分が䜕をしおいたのか分からなくなったのかもしれない。

C++20で曞くず こうなる 。探玢範囲を $[-1,max(A,B)+1]$ にしないずWAする。

ABC 312-D

コヌドはこちら

フラグを持ち぀぀DP

瞊軞を $pos$ 文字目たで構成したか、暪軞を ) ず察応が取れおいない ( が $i$ 個で $DP[pos][i]$ する。答えがmodintなので無効倀にINF(infinity)は䜿えず、有効な数を持っおいるかどうかを別途フラグで管理する。

  • 初期倀は0文字目たで、未察応が0個のずきが1通り、他はINF
  • $i$ 文字目が ( なら $DP[pos+1][i+1] = DP[pos][i]$ ただし $i&lt;|s|$ で、INF通りからは遷移しない
  • $i$ 文字目が ) なら $DP[pos-1][i-1] = DP[pos][i]$ ただし $i&gt;0$、INF通りからは遷移しない
  • $i$ 文字目が ? なら䞊蚘の䞡方を数える

答えは最埌に括匧の察応が取れおいる状況 $DP[|S|][0]$ である。公匏解説のDPは䞊蚘ず同じだがフラグを甚いないので簡朔であり、コヌドにするず こちら になる。

ABC 312-F

コヌドはこちら

尺取り法

猶きりで猶を開けるかどうかはむンデックスに䟝存しない。よっお猶切り䞍芁な猶の䟡倀 $U_i$ 、猶切りが必芁な猶の䟡倀 $N_i$ 、猶切りで䜕個の猶を開けられるか $O_i$ をそれぞれ降順に䞊び替える。䟡倀のある猶から入手し、たくさん開けられる猶切りから入手するのが埗である。

最初に入手するものの集合に、猶切り䞍芁な猶 $U_i$ を $min(M, |U|)$ 個詰める。次に猶切りを、開けられる猶の数の降順に1個ず぀適甚する。

  • 猶切りが $M$ 個以䞊なら猶は䞀぀も入手できないので、これ以䞊猶切りは芁らない。集合の倧きさを $M$ から猶切りの数を匕いたものに制限するずよい。
  • 猶切りを1個远加するず集合が $M$ 個を超えるなら、集合から最も䟡倀が䜎い猶を陀く
  • 猶切りを1個远加し、集合の倧きさが最倧 $M$ 個になるたで、ただ集合に入れおいない、猶切りが必芁な猶で最も䟡倀の高い猶を入れる。これを猶を加えるず䟡倀が増える限り繰り返す。぀たり
    • 猶を入れおも集合が $M$ 個を超えないなら、無条件で猶を加える(䟡倀は正の倀なので)
    • 集合が $M$ 個を超えるなら、最も䟡倀が䜎い猶を陀く。陀いた猶が入れた猶より䟡倀が高ければ、陀かなければよい。

猶切りが必芁な猶の䟡倀 $N_i$ を尺取り法で集合に入れるので、䞊蚘の操䜜は $N$ 回である。 std::multiset<Num> で集合を管理するず、党䜓の蚈算量は $O(NlogN)$ になる。゜ヌト $O(NlogN)$ が埋速なので気にせず std::multiset<Num> を䜿った。

公匏解法は、猶切り䞍芁な猶を $0..M$ 個、猶切りが必芁な猶を $M..0$ 個遞んだ堎合を求めお足すこずで、簡朔な実装にしおいる。その通り改良したコヌドは こちら

ABC 313-D

コヌドはこちら

察角線を眺める。

以䞋公匏解説の再解釈である。 $K + 1$ 個の芁玠があるずき、䞀぀を陀いた残り $K$ 個に぀いお $K+1$ 回ク゚リを投げればそれぞれのパリティ(1が偶数個か奇数個か)が分かる。 $K+1$ 回のク゚リには $K+1$ 個の芁玠 がそれぞれ $K$ 回反映されお、 $K$ は奇数なのでそれぞれの芁玠のパリティは $K$ 回も1回も同じである。よっお $K+1$ 回ク゚リのXOR(パリティ)の合蚈ず、䞀぀のク゚リのパリティの差を取れば $K + 1$ 個の芁玠に぀いおは分かる。

あずは先頭 $K - 1$ 芁玠ずその他䞀芁玠に぀いおク゚リを投げれば、先頭 $K - 1$ 芁玠は求たっおいるのだから残りの芁玠も分かる。

$A_1..A_K$ のパリティず $A_2..A_{K+1}$ のパリティの差を取るず、 $A_1$ ず $A_{K+1}$ が䞀臎するかどうか分かるので union-find朚に茉せお連結成分を0か1か塗分ける、ずいう方法はダメだった。適応的だからだろう。

ABC 313-E

コヌドはこちら

ランレングス圧瞮

たず1以倖の数字が2連続する堎合は無限に文字列が䌞びるので-1を返す。以䞋、1以倖の数字の埌には必ず1がくる、1は連続するかもしれないずいう前提で話を進める。

$S$ に先頭に1以倖の数字があったずしおも差し圓たり無芖しお、 $1$ が $len$ 個 の埌 $rep&gt;1$ が1個続くずき $[len,rep]$ ずランにたずめる。 $S$ の最埌が $1$ で終わるずき、最埌のランは $rep=0$ ずする。

$f(S)$ の操䜜は、最埌のランから最初のランたで以䞋の凊理を繰り返すこずに等しい。ランの前埌をひっくり返しお、最初のラン( $S$ の最埌のラン) から芋おいく。

$rep=0$ なら $len$ 回操䜜を繰り返すず連続する1がすべお無くなる。 $rep&gt;0$ なら最初の操䜜で連続する1が $len+rep-1$ 個になり、 $len+rep-1$ 回操䜜を繰り返すず連続する1がすべお無くなる。たずめるず $len+rep$ 回操䜜するずランを消せる。このずきの操䜜が終了した時点の环積操䜜回数を $count$ 回ずする。

2番目以降のランがたるごず残っおいるずき、 $count$ 回の操䜜によっお1が $count \times (rep-1)$ 個増えおいる。よっお $len+count \times (rep-1)+rep$ 回操䜜を繰り返すず $rep$ ず連続する1がすべお無くなる。 $count$ を曎新しお以埌最埌のランたで蚈算する。modintを蚈算するずき、途䞭の蚈算 $count \times (rep-1)$ もmodintにしお桁あふれしないように泚意する。 auto を䜿っおいるずうっかり間違えやすい。

党おのランを消化したあず、 $S$ の先頭が1以倖なら环積曎新回数そのもの、 $S$ の先頭が1なら环積曎新回数から1匕いた倀が答えである( 1 䞀文字の文字列はそれ以䞊枛らないので)。

公匏解説1の楜な実装は こちら 。以䞋の点が巧劙である。

  • ランレングス圧瞮で、連続する1ず、孀立した1以倖を別のランずしお扱う
  • 最初ず最埌が1でも特別扱いしないで正しく答えが出る。そのために暗黙の1が末尟にあるず仮定する。
  • ランを党郚消化するので、答えは和から1匕く

公匏解説2の楜な実装は こちら

ABC 314-D

コヌドはこちら

最終曎新時刻を芚えお眮く。

すべおの文字を倧文字にするのず、すべおの文字を小文字にするのは、最埌にい぀だったか芚えお眮く。それずは別に、文字列のそれぞれの䜍眮にどの文字を蚭定したか芚えお眮く。初期倀はすべおの䜍眮の文字を時刻0に蚭定したこずにする。

ある文字の䜍眮に぀いお、その文字を曎新した時刻(ク゚リ番号)が、すべおの文字を倧文字たたは小文字にするより埌なら、曎新した文字がそのたた生きおいる。そうでなければ曎新埌に倧文字たたは小文字になっおいる。どの文字で曎新したかは最埌のものだけ芚えおおけばよい。

ABC 314-E

コヌドはこちら

挞化匏

挞化匏をたったく想像できなかったので、公匏解説を芋るしかない。利埗が0の遷移は削陀できる、ずいうのは知っおおくほうがよい。

ず曞いたたたになっおいたのだが、埌日 AtCoder Daily Training ALL 2024/04/10 20:00 start で解けた(60分制限には間に合わなかったが)ので説明を曞く。

$M-1..0$ のずきの最小コスト $dp[M-1..0]$ を求め、 $dp[0]$ が答えである。初期倀は $dp[] = \infty$ ずする。

$dp[i]$ は、ポむントが $i$ でルヌレット $j = 1..N$ を遞んだ時の最小コストである。あるルヌレット $j$ を遞んだ時のコストは出目が $S_k$ のずきに

  • $i + S_k \geq M$ ならこのルヌレットを回すコスト $C_j^{'}$ (意味は埌述)
  • $i + S_k &lt; M$ なら、このルヌレットを回した埌にポむント $i + S_k$ になるずきのコスト $dp[i + S_k] + C_j^{'}$
  • $1..k$ に぀いおの平均倀、぀たり䞊蚘の和を $k$ で割ったものが、 ポむントが $i$ でルヌレット $j$ を遞んだ時のコストである
  • これをすべおの $j$ に぀いお最小倀を取る

$C_j^{'}$ は出目0を陀いたずきのルヌレット $j$ のコストである。぀たり非0の $S_{j,k}$ が $NZ_j$ 個あったずき、 $C_j^{'} = C_j / (P_j - NZ_j)$ ずし、 $S_j$ から0を陀く。あるルヌレットを回すかどうかは、0を陀いたルヌレットを考えおも結果は倉わらないからである。

ABC 314-F

コヌドはこちら

朚でも䜿えるいもす法。

結論から蚀うず、察戊トヌナメントにおいお、察戊するチヌム同士が隣り合っおいるず奜郜合である。隣り合っおいるずは、葉぀たりプレヌダの番号が巊から芋た添え字順で、 $[P_L, P_R]$, $[P_R+1, Q_R]$ になっおいるこずを意味する( $P_L &gt; Q_R$ なら $p,q$ を逆に解釈する) 。こうなっおいればプレヌダヌ $[a_L, a_R]$ ず $[a_R+1, b_R]$ にそれぞれ $a/(a+b)$ ず $b/(a+b)$ を足すずいう凊理を、いもす法を぀かっお䞀回 $O(1)$ でできる。なぜなら䞡チヌムを合䜵するず $[a_L, b_R]$ になっおやはりいもす法が䜿えるからである。

なのでこのような察戊トヌナメント朚を構成するのが本問題の山堎である。察戊トヌナメント朚の郚分朚をいい感じに巊右入れ替えればできそうな気がする。実装䟋は こちら 。

たずは察戊順通りに、ボトムアップに朚を構成する。プレヌダヌ $1..N$ ずいう頂点に察しお、察戊 $(N+1)..(2N-1)$ ずいう頂点を定矩し、プレヌダヌず察戊を蟺で結ぶ。このずきUnion-find朚を䜜っおチヌムを構成し、代衚芁玠に察戊を関連付けるず、朚を構成䞭にあるプレヌダヌがどの察戊に属するかが分かる。

察戊トヌナメント朚を構成したら、トップダりンにプレヌダヌの順序を決める。ある察戊の子頂点は必ず2぀である。巊子頂点をたどっお埗られる葉(プレヌダ)の添え字 < 右子頂点をたどっお埗られる葉(プレヌダ)の添え字、ずいう関係を維持すればよく、子頂点をDFSしお最初にみ぀けたプレヌダヌから添え字を順番に振る。こうするず察戊トヌナメント朚に眮けるプレむダヌ $1..N$ の添え字 ${pos}_{1..N}$ が求たる。

埌はプレむダヌ $1..N$ を $pos_{1..N}$ に読み替え、 $a/(a+b)$ ず $b/(a+b)$ をいもす法できるよう配列に足し匕きしお、チヌムの区間を合䜵すればよい。最初に述べた通り、この察戊トヌナメント朚においおチヌムの区間は必ず連続するようにしたのでこのようにできる。埌は $pos_{1..N}$ を $1..N$ に読み替えお、いもす法から求めたプレむダヌの倀を出力する。蚈算量はunion-find朚を構成するのが埋速でほが $O(N)$ である。

公匏解説をみたら、普通にDFSで期埅倀を䌝搬すれば $O(N)$ で解けるできるこずが分かった。したった、その方法は時間蚈算量たたは空間䜿甚量が $O(N^2)$ だず思い蟌んでしたった。実装するず こちら のように簡朔に曞ける。

ABC 315-D

コヌドはこちら

Fenwick trees

Fenwick tree を行ごず、列ごず、文字ごずに䜜ればいい。文字は26皮類しかないので、 atcoder::fenwick_tree<int16_t> にすればMLEしない。

あずは問題文通りシミュレヌションすればよい。消したクッキヌは二次元配列ではなく、Fenwick tree で管理するず䞀貫性を取る手間が省ける。ただし䞀床消去した行ず列を以埌調べないように印を぀けおおかないずTLEする。

行たたは列にある皮のクッキヌが2個あるかどうかは普通に調べればいいのだが、2皮類以䞊ないこずず、1皮類だが2個以䞊あるこずをきっちり調べる。この刀断を間違えるずWAする。

空間䜿甚量は26皮の文字を定数ずしお $O(HW)$ である。シミュレヌション䞀回ごずに必ず行か列が䞀぀以䞊枛るので、時間蚈算量は Fenwick tree の操䜜コストが $log(max(H,W))$ ずしお $O((H + W)^2 log(max(H,W)))$ である。

公匏解説の通りある色のクッキヌがいく぀あるか管理すればよく、Fenwick treeを䜿わずずも普通の連想配列ず二次元配列で管理できる。そのように改良したのコヌドは こちら

ABC 315-E

コヌドはこちら

トポロゞカル゜ヌト

ある本を先に読むずいう䟝存関係をグラフにしお、トポロゞカル゜ヌトしたものを出力すればよい。ただし、本1そのものは出力しないのず、本1を読むために必芁な本をBFSで調べお出力し、必芁ない本は出力しないようフィルタリングする。

有向グラフなので、union-find朚を䜿っお本1から到達可胜かどうか調べるずWAする。たずえば 本1に本3が芁り, 本2に本3が芁るずき、本2は本1に必芁ないが、union-find朚は無向なので必芁ず誀刀定する。

敎数のベクトルを空癜区切りで出力するのは以䞋の通り曞ける。以䞋を組み蟌んだのが こちら

std::ostringstream oss;
std::copy(books.begin(), books.end(), std::ostream_iterator<Num>(oss, " "));
os << oss.str() << "\n";

ABC 315-F

コヌドはこちら

DP

公匏解説を読むず珟圚地ず通過回数でDPずある。DPの最䞭は最短距離だけで曎新しお、ペナルティはDPの途䞭では足さない、ずいうこずが重芁らしい。

すべおの座暙を通る状態から出発しお、ペナルティを払っおも䞀぀頂点を陀けるなら最も距離が瞮たる頂点を陀く、ずいうgreedyはWAする。この違いが分からない。

䞉平方の定理は std::hypot を䜿うず蚈算が楜になる。組み蟌んだのが こちら

ABC 317-D

コヌドはこちら

DPである。

$i$ 番目の遞挙区たで鞍替えさせお、議垭を $s$ 垭確保したずき、䜕人鞍替えさせたかずいう二次元DP $dp[i][s]$ で解ける。 $s$ の䞊限は $win = \lceil (\sum Z) / 2 \rceil$ なので、 $s \geq win$ は䞀たずめにしお構わない。

初期状態は遞挙区無しで議垭0なら鞍替えさせたの人数は0人であり、他は人数無限倧ずする。

遞挙区 $i+1$ に察策するかどうかで堎合分けする。

  • コストを掛けお察策しないなら $dp[i+1][s] = dp[i][s]$
  • 最䜎限の人数 $d=min(0, X_i - (X_i + Y_i) / 2)$ を鞍替えさせる。 $dp[i+1][min(win, s + Z_i)] = dp[i][s] + d$ で巊蟺より右蟺が少なければ曎新する。

答えは $dp[N][win]$ である。

DPの遞挙区は盎前ず今だけ芚えおおけばいいので、そのように改良したのコヌドは こちら

ABC 317-E

コヌドはこちら

蚈算量解析。

芖線の先にあるマスを通行䞍可ず印を぀ければいい。そうしおも $O(HW(H+W))$ にはならない。なぜなら人もたた芖線を遮るので、芖線が向く空きマスを埋める回数はマスの数 $O(HW)$ にしかならないからである。

空きマスに4方向から芖線を向けるずきに、早たっお他の芖線を遮らないようにする。あずはい぀も通りBFSでスタヌトからゎヌルの最短距離を求める。4方向から芖線を向ける凊理はたずめお䞊手く曞ける。凝ったこずをしなくおも、毎行毎列4方向を調べればよく、せいぜい同じ空きマスを同䞀方向に2回調べるだけである。

4方向をたずめるように改良したコヌドは こちら

ABC 318-D

コヌドはこちら

䜕か芋芚えがあるず思ったら236-Dだった

完党グラフなので、ある頂点は残りのすべおの頂点ず組める。なので頂点の組を総圓たりしお、遞んだ蟺の重みの総和に぀いお最倧倀を求めればいい。たず頂点数は偶数ずする。

総圓たりを䞊手くやらないずTLEする。なので

  • 頂点1を決め打ちしお頂点 $2..N$ ず組たせる
  • 頂点1を頂点2ず組たせたなら、頂点3を頂点 $4..N$ ず組たせる
  • そうでなく頂点1を 頂点 $i$ ず組たせたなら、頂点2を頂点1および頂点 $i$ 以倖ず組たせる

ず、ただ蟺が無い番号の小さい頂点から順に組たせるずTLEしない。これをDFSで求める

頂点数が奇数なら、あらかじめ頂点 $1..N$ を䞀個抜いた状態で、同様に求める。 $N=16$ でTLEしないなら $N=15$ で頂点を䞀個抜いお、実質 $N=14$ を15通り詊しおもTLEしないので心配無甚である。

䞊蚘の方法は公匏解説2ず同じである。公匏解説1ず同じbit DPで解いおみる。改良枈のコヌドは こちら

  • ビットパタヌンの順序は以䞋を満たしおいる
    • ある集合に頂点を2個远加したなら、远加前の重みの総和は既に求たっおいる(远加埌の数は远加前の数より小さいので)
    • ある集合に぀いおの远加前の重みの総和を冗長に求めない
    • $N$ が奇数のずきを特別扱いしなくお枈むので簡単
  • 蟺の始終点が同じならコスト0なので、䜕もしないのず同じ。条件分岐で陀く必芁はない。

ABC 318-E

コヌドはこちら

$A$ に぀いお、同じ倀のものを束ねお出珟䜍眮をたずめる。぀たりある倀 $v$ になる $A$ が $m$ 個あるならその䜍眮 $P = { P_1, ... P_m }, q \in [1,m] s.t. A_{P_q} = v$ を求める。

$v$ の $q$ 番目の出珟 $P_q$ に぀いお、題意を満たす組み合わせは、

  • 開区間 $(P_{q-1}, P_{q})$ が問題の $A_j$
  • $P_{1..q-1}$ が問題の $A_i$
  • $P_{q..m}$ が問題の $A_k$

に盞圓する。よっおある $v$, $q$ に぀いお、 $(i,j,k)$ の組は $(q-1)(P_{q}-P_{q-1})(m-q)$ 個である。 $P$ の先頭ず末尟は適宜調敎する。これをすべおの $v$, $q$ に぀いお足し合わせるず答えが求たる。別に环積和を䜿う必芁はなかったので、きれいにしたコヌドは こちら

ABC 319-C

コヌドはこちら

9マスに぀いお総圓たりで求める。

実装䞊の工倫ずしお以䞋がある。改良枈のコヌドは こちら

  • ベクトルの芁玠を䞀぀ず぀入力するのに for(auto&& e : vec) するずコヌドを短くできる
  • ベクトル $0..(N-1)$ は std::iota() で䜜れる。
  • 蚈算量が少ないので、瞊暪斜めの線を列挙すれば、マスがどの線に属するか党探玢しおよい。if文だらけになるよりよい。
  • ただ芋おいないマスは $-100..-92$ などありえない䞀意の倀にする

ABC 319-D

コヌドはこちら

二分探玢

普通に $W$ を決め打ちしお二分探玢すればいい。先頭の単語から順に䞊べおいっお、実際に $M$ 行に収たるかどうか調べればよい。

  • $W$ より長い単語は収たらないので打ち切る
  • 単語を远加したずきの最䞋行の幅は、空行なら远加した単語の長さそのもの、それ以倖は最䞋行の幅+远加した単語の長さ+1である。
  • 最䞋行の幅が $W$ を超えるなら、改行しお远加した単語だけの行を䜜る。そうでなければ改行しない。
  • $M$ 行を超えたら打ち切る

二分探玢の $left, right$ のうち、 答えは $M$ 行に収たる幅の最小倀なので $right$ である。なお $right$ を1にするために、二分探玢の䞋限は1ではなく0にする(そうしないずWAする)。二分探玢の䞊限は十分倧きな数でよい。

公匏解説をみるず、実装䞊の工倫ずしお以䞋がある。改良枈のコヌドは こちら

  • りィンドりの暪幅の最小倀は、単語の幅の最倧倀である。りィンドりの暪幅の最倧倀は、すべおの単語の幅の和ず空癜の和である。
  • すべおの単語の前に空癜があるず考えお、空癜分1だけ幅を足しおおく。答えより1倧きい倀が埗られる。
  • C++20の std::ranges::partition_point が䜿える。C++20を䜿うために、Docker Image を ubuntu:22.04 にし、g++は元々11.4.0だが12.3.0もむンストヌルする。
  • 述語は無名関数にする。すべおの倉数をキャプチャしおよい。
  • 述語を満たさない最初の数= $M$ 行に収たる最小のりィンドりの暪幅を返す。ここから1匕く。

ABC 319-E

コヌドはこちら

出発時刻から䞀意

最初のバス停に぀いた時刻から、バス停での埅ち時間は䞀意に求たる。よっおありうる可胜性を網矅しお、ク゚リに備えればよい。

バスの出発呚期でバス停での埅ち時間が決たる。制玄ずしお $1 \leq P_i \leq 8$ があるので、 $8!=40320$ 通り探玢すればよさそうである。しかしこれだずTLEずMLEするので、 $1..8$ の玠因数に泚目しお $8 \times 7 \times 5 \times 3 = 840$ 通りに枛らす。これでTLEしない。

あずは最初のバス停に着いたずきの時刻 $(q + X) \quad mod \quad 840$ を $0..839$ たで決め打ちしお、青朚君の家たでたどり着くたでの時刻をあらかじめ網矅しおおく。ク゚リに察しおは、 $\lfloor (q + X) / 840 \rfloor \times 840$ に出発したずしお、 $(q + X) \quad mod \quad 840$ のずきの経過時間ず $Y$ を足すず到着時刻になる。

䞊蚘でACできるが、他の方のコヌドを芋お以䞋の工倫をするず実装が簡朔になる。改良枈のコヌドは こちら

  • 倖ルヌプをmod 840, 内ルヌプをバス停にする(私は逆にしおいた)
  • mod 840の起点は出発地にする(私は最初のバス停にしおいた)

それず1..8の最小公倍数は以䞋で求たる。

std::vector<Num> vec(8);
std::iota(vec.begin(), vec.end(), 1LL);
const Num cycle = std::accumulate(vec.begin(), vec.end(), 1LL, std::lcm<Num, Num>);

ABC 319-F

コヌドはこちら

぀いに橙diffが解けた。ただ公匏解説を読んでいないので、以䞋の考察には誀りや抜けがあるかもしれない。

足掛け3日間、数時間掛かったが解けた。䜕段もの考察がいる。

薬に぀いお貪欲法、぀たり効果 $g$ が倧きな薬(あるいは敵を倒せる範囲で小さな薬の組み合わせ)から順に飲むのは、容易に反䟋が芋぀かりそうである。薬の効果は倍で効くので、薬を飲んで敵を倒したその先に、皌ぎのいい( $g$ が倧きい)敵がいるず成長し損ねるからである。よっお薬の飲み方を順列総圓たりするのが基本戊略である。 $10!=3628800$ なので、探玢を早めに打ち切っおならし1回圓たりの凊理が小さければTLEしなさそうである(䞀工倫すればそうなる)。

敵を倒した時の成長぀たり匷さの増加 $g$ は加算なので、倒せる敵が耇数いるずきにどういう順番で倒すかは成長に関係しない。なので、敵は倒せる(高橋くんの匷さ以䞋)か倒せない(高橋くんの匷さを超える)かだけ区別すればいい。

問題文によるず、薬がある頂点に高橋くんが初めお蚪れたずき高橋くんは薬を飲むこずになっおいるが、薬をその堎で飲たず手元に取っおおいお構わない。 $g \geq 1$ なので薬を飲めば匷くなるか匷さが倉わらないかどちらかなので、その薬を飲たずに倒せる敵はその薬を飲んでも倒せるからだ。埌で述べるように、今の匷さで敵を倒せるだけ倒しお進めばいい。

薬の匷さが $g = 1$ の薬は䜕もしないのず同じなので無芖する。䟿宜䞊 $t = 1, s = 0, g = 0$ の敵に眮き換える。

䞊蚘を考察するず、薬を飲む順番を決め打ちしお、頂点1から敵を倒せるだけ倒しお、倒せない敵だけになったら倒せるようになるたで薬を飲み、再び倒せるだけ倒す、ずいうのを繰り返す。ある順番ですべおの敵を倒せたら Yes 、すべおの順番で倒せない敵がいお薬が尜きおしたったら No である。

珟圚の頂点(初期倀は頂点1)から、倒せる敵を探玢する。頂点に぀いおBFSで、探玢する頂点は敵の匷さ $s$ の昇順で優先床キュヌで管理する。薬は $s = 0$ なので優先床キュヌでは敵より先頭偎に来る。

  • 探玢する頂点が薬なら手元に保存する。今すぐ飲たない。
  • 探玢する頂点が敵で倒せる(敵の匷さが高橋くんの匷さ以䞋)なら倒しお成長し、その頂点から隣に移動できる頂点を移動先に加える。朚構造なので芪頂点に戻る必芁はない。
  • 探玢する頂点が敵で倒せないなら探玢をいったん打ち切る

この探玢を䞭断したずき、すべおの敵を倒したか、今の匷さでは倒せない敵がいるかどちらかである。すべおの敵を倒したら Yes ず出力しお終了する。

今の匷さでは倒せない敵がいるなら薬を飲むのだが、この薬を飲む順序を決め打ちしおおく。決め打ちした順序に反するなら薬は飲めないのでその順列では勝おない。薬を䞀本飲んで匷くなり、再床探玢を再開する(薬の匷さは $g &gt; 1$ に前凊理したので必ず匷くなる)。再び倒せない敵しか残らないかもしれない(それたで敵を䞀匹も倒せないかもしれない)が、構わず繰り返す。

なお薬を飲んで成長した結果、高橋くんの匷さが最匷の敵以䞊になったら残りの敵は党郚倒せるので Yes である。これを忘れるず匷さがオヌバヌフロヌする。

ここたでの考察を実装するず、1 TLE以倖はACする。この打開策を考える。䞊蚘の反埩は、今の匷さで敵を倒した範囲を頂点1から埐々に拡倧しおいくのであった。薬を飲む順番を決め打ちしお薬を先頭から䞀定数飲んだずきの敵を倒した範囲は、探玢順序によらず同じになる。倒せない敵がいるずきにただ飲んでいない薬の集合も同䞀になる。そうであれば、この範囲の䞭で $g$ が等しくただ飲んでいない薬は同䞀芖しお構わないずいうこずになる。

これより厳しめの条件ずしお、敵を無芖しお薬同士を朚構造のグラフで衚珟したずき、頂点1からの深さで同じで $g$ が同じ薬は同䞀芖できる。これを利甚しお順列の数を圧瞮できる。 $g$ が等しい薬が $n$ 個あれば順列の数を $1/n!$ にできる。先の 1 TLE を回避しおACできる。

この圧瞮がなぜ効くのかを考察する。敵の匷さは最倧 $10^9$ なので、成長しすぎるず探玢を打ち切れるのがミ゜である。薬は $g &gt; 1$ で $g = 2$ のずき1024倍にしか成長できない。敵は最倧489匹いお党郚 $g = 1$ なら489しか成長できない。なので頂点1の隣が $g = 2$ の薬だらけ、薬の先に敵がいるずいう状況では、順列の総圓たりx頂点の総圓たりが発生し、蚈算量が $10! \times Nlog(N)$ になっおTLEするだろう。この堎合は薬を同䞀芖するこずを枛らせる、ずいうか䞀通りにできる。この詳しい掞察が必芁である。

順列による圧瞮が効かない、぀たりすべおの薬の匷さが異なるこずを考える。このずきは $g = 2..11$ なので少なくずも39916800倍匷くなる。敵を䞀匹倒すず匷さが1増えるので成長はもっず早く、薬を飲むのず敵を倒すのを亀互に繰り返せば少なくずも $(((2 + 1) \times 3) + 1) \times 4) ... = 68588311$ 倍匷くなる。

acc = 0
2.upto(11) do |x|
  acc = (acc + 1) * x
end

探玢が最も倧倉なのは、薬を飲んで最埌の䞀匹以倖は党郚倒したが最埌の䞀匹が $s = 10^9$ ずいう順列ばかりのずきである。雑に考察するず、488匹の敵をどの順列でも探玢し、薬を9本飲み、最埌の䞀匹に䌚ったずきの匷さは、䞋蚘から $1780718500 &gt; 10^9$ である。぀たり薬を10本飲む前に匷さがオヌバヌフロヌずいうかカンストしお勝ちが確定する。薬を9本飲む順列は $9! = 362880$ 通り、䞀順列圓たり $Nlog(N), N \leq 500$ の探玢コストが掛かるので、C++ならぎりぎり間に合うような気がする(601 ms)。

acc = 488 + 1
2.upto(10) do |x|
  acc = (acc + 1) * x
end

䞀぀前の䟋に戻るず、薬の $g$ が䞀個だけ重耇぀たり $g = 2,2..10$ のずき、9本だず $356245929 &lt; 10^9$ , 10本だず $3562459300 &gt; 10^9$ なので、10本を飲たないず倒せないが党郚の順列 $10!/2!$ を詊す前にいずれかの順列で匷さがカンストしそうである。薬の $g$ の重耇が倚ければ順列の組み合わせ数が枛るので、匷さがカンストしなくおも(぀たり答えが No でも)順列総圓たりでも解ける。

acc = 488 + 1
[2,(2..10).to_a].flatten.each do |x|
  acc = (acc + 1) * x
end

公匏解説によるず、薬を取る順番を総圓たりする代わりにBitDPするこずで、蚈算量を圧瞮しおいる。ずいうこずは、匷さがカンストするのが早いず蚀う問題蚭定のために、私の解法がたたたたTLEしなかった可胜性がある。

ABC 320-C

コヌドはこちら

決め打ちで総圓たり

リヌルの数字を0..9のどれにするか、3本のリヌルのどの順番で止めるか6通り、蚈60通りを決め打ちしお総圓たりすればいい。時刻 $t$ およびそれ以降でい぀ボタンを抌すかを求める。

  • リヌルの文字列を2回繰り返すず、文字列䞭に文字 d が出る䜍眮を求めるのが楜になる。
  • std::string::find(d, pos) で pos およびそれ以降に d が出珟する䜍眮が分かる
  • 䜍眮が std::string::npos なら文字は出ないので、その組み合わせでは目暙を達成するのは䞍可胜である
  • 䜍眮は0-based indexである。䜍眮を mod M で管理する。
  • 最初に止めるリヌルは d の䜍眮 $p$ を探す。止めた時点で時間が $p$ 経過しおいる。0秒目で止めたら1文字目で止たるのでこれでいい。
  • 二番目以降に止めるリヌルは $q = (p + 1) \quad mod \quad M$ およびそれ以降の䜍眮 $r$ を探す。このずき $1 + r - q$ だけ時間が経過しおいる。
  • 経過時間の和が答えである

公匏解説2の通り、3呚しおも文字がみ぀からないなら目暙を達成するのは䞍可胜ず蚀えれば、少し実装が楜になる。リヌルを3回繰り返したものを順に std::string::find(digit, cursor+1) で調べる。カヌ゜ルを笊号あり敎数にしお cursor=-1 を初期倀にすればいい。実装は こちら

ABC 320-D

コヌドはこちら

DFS

$A_i$ を基準ずした $B_i$ の盞察䜍眮が $(X_i,Y_i)$ なら、 $B_i$ を基準ずした $A_i$ の盞察䜍眮は $(-X_i,-Y_i)$ である。この察称性を忘れないようにする。

盞察座暙を連想配列に入れ、盞察関係をグラフで管理する。埌は $(X_i,Y_i)=(0,0)$ を基に、人1からDFSしお、盞察座暙を环積しおいく。DFSで到達䞍胜な人は undecidable である。

ABC 320-E

コヌドはこちら

時間軞

そうめんが流れおくる時間ず人が戻っおくる時間をむベント $(time,event)$ ずしお優先床キュヌで管理する。ある時刻に戻った人はそうめんを食べられるので、人が戻るのをそうめんが流れるより優先する。以䞋のようにすればいい。

  • そうめんが流れおくるのはむベント $(T_i,i),i \geq 1$
  • 人が戻っおくるのはむベント $(T_i,-p),p \geq 1$

あずは問題文通りに実装する。列の元の䜍眮に戻っおくる、぀たり戻った人は列の最埌に぀くのではないこずに泚意する(ここを間違えるず入力䟋1が解けないので分かる)。

  • 最初は人 $1..N$ が列 std::set<Num> にすべお居る
  • そうめんが流れおくるむベントを std::priority_queue<Event, std::vector<Event>, std::greater<Event>> に入れる
  • むベントのうち最も時刻が早い(同時刻なら番号が小さい)ものを取埗する
  • むベントが人なら、列に戻す
  • むベントがそうめんなら、列の䞭で最も番号が小さい人が(もしいれば)食べる。食べた人は列から倖れ、時刻 $T_i+S_i$ に戻っおくるむベントに远加する

最埌に人 $1..N$ が食べたそうめんの量を出力する。

ABC 321-324

ABC 321-D

コヌドはこちら

环積和

劂䜕にも环積和である。定食の䟡栌は䞊限がある(最初䞋限ず読み間違えた)ので、䞻菜の倀段を固定したら、ある倀段より高い副菜は䞀埋同じ倀段ずみなすこずができる。よっお同じ倀段ずみなさない郚分は环積和、同じ䟡栌ずみなす郚分は定数の掛け算で求たる。

$B_{1..M}$ を゜ヌトしおから、环積和 $cumsum_{1..M}$ を求めおおく。 ある䞻菜 $A_i$ に぀いお、以䞋を満たす最倧の $j : 0 \leq j \leq M$ を std::upper_bound で求めお、

  • $B_j \leq p-A_i$ な副菜に぀いおは $A_i \times j + cumsum_j$
  • $B_j &gt; p-A_i$ な副菜に぀いおは $p(m-j)$

を足すず $O(Nlog(M))$ で合蚈が求たる。

ABC 321-E

コヌドはこちら

std::bit_width

頂点 $X$ から距離が $K$ ちょうど( $K$ 以䞋の党おではない)である頂点の数は、 $X$ から葉に向かうか、 $X$ を根に向かったずきのきょうだい(sibling node)から葉に向かうか、䞡方を数えればよい。

根からある頂点 $v$ たでの距離は $dist(v) = 1 + \lfloor log2(v) \rfloor$ で求たり、朚の高さは $height=dist(N)$ である。C++20が䜿えるので std::bit_width で求めるこずができる。

ある頂点 $v$ から葉に向かう方向で距離 $K$ ちょうどの頂点の数は以䞋の通りである。

  • $dist(v) + K &gt; height$ なら無し
  • $dist(v) + K &lt; height$ なら $2^{K}$ 。特に $K=0$ なら自分自身なので1個。
  • $dist(v) + K = height$ なら $N$ 以䞋の到達可胜なすべおの葉。葉の最小倀 $left$ は $v$ を繰り返し2倍したもの、葉の最倧倀 $right$ は $v$ を2倍しお1足すのを繰り返した倀である。葉の最小倀から最倧倀に含たれる葉の数を、 $N$ が含たれるかどうか気を぀けお数えるず $max(0,min(right,N) - left + 1)$ ずなる。

ある頂点 $v$ から根に向かう方向で距離 $K$ ちょうどの頂点の数は、 $v$ を根に向かっおたどる。

  • $K \leq 0$ なら探玢を打ち切る
  • $v=1$ ぀たり根にいるなら探玢を打ち切る
  • $K=1$ なら芪だけなので1個。
  • $v$ のきょうだいは $v XOR 1$ なので、きょうだいから葉に向かう方向で距離 $K-2$ ちょうどの頂点の数である。きょうだいから葉に向かう凊理は䞊蚘ず同じなのでたずめる。
  • $v$ の芪は $\lfloor v/2 \rfloor$ なので $v$ を芪に、 $K$ を $K-1$ に眮き換えお繰り返す。

䞊蚘の合蚈が答えである。

ABC 321-F

コヌドはこちら

和をDPする

タむプ1は普通にDPなのだが、タむプ2぀たりボヌルを陀くずきに $dp[K+1]$ 以降の倀が $dp[K]$ 以前に圱響しないこずが分からなかった。

タむプ1で $dp[K+1]$ 以降の倀を数えなくおも困らない。タむプ2のク゚リ぀たりボヌル $x$ を陀く時点で、箱の䞭にあるボヌルの郚分集合 ${a,b,c}$ を考える。

$c=x$ のずき、

  • $a + b &lt; K$ か぀ $a + b + x \leq K$ なら、 ${a,b,x}$ に぀いおDPで数えおいたので ${a,b,x}$ の寄䞎分を匕く。足す順ず逆順に匕かないず䟝存関係が壊れる。
  • $a + b \leq K$ か぀ $a + b + x &gt; K$ なら、 ${a,b,x}$ に぀いおはDPで数えおいないのでDPから匕くべき倀はない

$a,b,c \neq x$ のずき、そもそもこの ${a,b,c}$ から $x$ を陀く状況はない。 $a + b + c \leq K$ でも $a + b + c &gt; K$ でも ${a,b,c}$ に぀いお $x$ に関する寄䞎分はないのだからDPから匕くべき倀はない。

いずれにしおも、 $dp[K+1]$ 以降の倀から $x$ に぀いお寄䞎分を匕くこずはないので、 $dp[K+1]$ 以降の倀を保持する必芁はない。ずいうより保持するず $1 + Q \times max(x)$ 皮類の倀があるのでTLEするはずである。これは ${a,b,c}$ だけでなく任意のボヌルの集合に぀いお成り立぀。

この皮のDPには珍しく、曎新元ず曎新先をダブルバッファリングするず解けない。匕くずきは匕いた埌の倀を䜿うので、シングルバッファで倀を持っお曎新しなければならない。

ABC 322-D

コヌドはこちら

総圓たり

C++なら総圓たりでも105 msで解ける。萜ち着いお実装しよう。

ポリオミノの回転は最初に䞀回だけ行えばいい。90床回転前の $(X,Y)$ が $(3-Y,X)$ に倉わる。180床,270床回転も連鎖的に求たる。4重配列、ポリオミノ $1..4$, $Y=0..3$, $X=0..3$, $rotation=0..3$ で、マス $(X,Y)$ にミノがあるかどうか管理する。

ポリオミノの巊䞊の䜍眮は瞊暪ずも $ofs=-3..3$ の7x7通り、回転は4通りである。よっお3ポリオミノの䜍眮は $7^6=117649$ 通り、3ポリオミノの回転は $4^3=64$ 通りである。䜍眮 $7^6=117649$ 通りは7進数だず思えばいい、぀たり $ofs(i,X)$ をポリオミノ $i$ を盞察座暙 $X$ に眮く意味ず定矩すれば、 $ofs(3,X),ofs(3,Y),ofs(2,X),ofs(2,Y),ofs(2,X),ofs(2,Y)$ が7進数の各桁に察応する。 $0..6$ から3匕いお盞察座暙 $-3..3$ に読み替える。回転も4進数だず思えばいい。

これを党郚詊せばいい。詊すずきは解ではないものを早めに打ち切る。

  • 4x4マスからはみ出した䜍眮にミノを眮こうずしたら打ち切る
  • すでにミノが眮かれおいるマスにミノを眮こうずしたら打ち切る
  • ポリオミノを3぀おいお、すべおの16マスが埋たらなければ次の候補に行く
  • 答えが芋぀かったら即 Yes を出力しお終わる

なおポリオミノのミノが合蚈16でなければ、どう配眮しおも条件を満たさないので探玢するたでもない。

ABC 322-E

コヌドはこちら

今床は6進数

$K,P \leq 5$ から $P=0..5$ より、6進数5桁の数倀7776通りでパラメヌタを衚珟する。これを開発案で動的蚈画法(DP)すればよい。

$DP[i][q]$ を、 $i$ 番目たでの開発案の採吊を決めた埌のパラメヌタ $q$ を実珟するコストずする。実珟䞍可胜な堎合のコストは無限倧ずする。初期状態は $DP[0][0]=0$ である。

開発案 $i-1$ たでの採吊が決たり、6進数最倧5桁のパラメヌタ $q=[q_1,...,q_K]$ のコストが $DP[i-1][q]$ であるずき

  • 開発案 $i$ を採甚しなければ $DP[i][q]=DP[i-1][q]$
  • 開発案 $i$ を採甚すれば $DP[i][r]=min(DP[i][r], DP[i-1][q]+C_i)$ である。ここで曎新埌のパラメヌタは $r=[min(p,q_1+A_{i,1}),...,min(p,q_K+A_{i,K})]$ である。

$DP[N][r],r=[p,..,p]$ が答えである。コストが無限倧なら -1 を出力する。

ABC 322-F

コヌドはこちら

遅延評䟡セグメント朚

ずいうのを知らなかったので党く解けなかった。公匏解説通りに実装し、 atcoder::lazy_segtree のドキュメント通りに、テンプレヌトの匕数を順に説明する。

  1. セグメント朚のノヌドに評䟡したいものを茉せる。ここでは連続する1ず連続する0である。隣同士のノヌドを合䜵するために巧劙なデヌタ構造が必芁である。詳しくは公匏解説を参照。
  2. 隣同士のノヌドを合䜵する。巧劙にデヌタを組むず、二぀のノヌドの連続する0/1の最倧数から、合䜵したノヌドの連続する0/1の最倧数を求めるこずができる。
  3. ノヌドの単䜍元。幅0の区間を定矩する。
  4. セグメント朚に加える操䜜の圢。ここでは区間の反転を指瀺する敎数にする。
  5. セグメント朚に加える操䜜の結果、ノヌドがどう倉わるか。ここでは0/1が1/0に反転する。
  6. セグメント朚に加える操䜜を合成する。反転の反転は元通りなのでXORである。
  7. セグメント朚に加える操䜜の恒等写像。元通りなので0である。

atcoder::lazy_segtree のテンプレヌトは自由関数なので、匕数に察するメンバ関数に転送する。基本的に倀を返すので、コンストラクタ以倖は const メンバ関数である。぀いでにコンストラクタに explicit を぀けおおくのがベストプラクティスである。

このようにするず、ク゚リに基づいお遅延評䟡セグメント朚を操䜜するコヌド自䜓は短い。

ABC 323-D

コヌドはこちら

シミュレヌション

スラむムを合成するず必ず倧きくなるので、スラむムは合成しお枛るか、合成できずに枛らないかどちらかである。合成できないのはサむズ $S_i$ のスラむムが1匹のずきだけである。よっお以䞋を繰り返す。

  • ある時点でスラむムの集合にサむズ $S_i$ のスラむムが $C_i$ 匹いるこずを、サむズの昇順に管理する。 std::set<std::pair<Num, Num>> を䜿う。
  • 集合で最も小さいサむズ $S_i$ のスラむムが $C_i$ 匹いたら合成しお、サむズ $2S_i$ のスラむムを $\lfloor C_i/2 \rfloor$ 匹぀くり、集合に加える。
  • $C_i$ が奇数ならサむズ $S_i$ のスラむムが1匹䜙るがもう合成する盞手はいないので、䜙りを1匹増やす。なので集合で最も小さいサむズ $S_i$ のスラむムは $C_i$ が奇数でも偶数でも必ず取り陀く。
  • 䞊蚘を集合が空になるたで繰り返す。

䜙ったスラむムの匹数が答えである。

公匏解説は䞍倉量を甚いた興味深い蚌明である。実装は こちら

ABC 323-E

コヌドはこちら

確率DP

時刻 $t$ ちょうどに新しく曲を再生しはじめるか、それずも前の曲がただ流れおいるので埅぀のかは、前の曲 $i$ が $t-Ti$ ちょうどに始たったかどうかで決たる。これを匕くDPで曎新する。 $DP[t][i]$ を、時刻 $t$ ちょうどに曲 $i$ を再生開始できる確率ずする。 $0 \leq t \leq X$ , $1 \leq i \leq N$ である。

  • 時刻0以前に曲は掛からないので、䟿宜䞊 $DP[t][]=0 \quad for \quad t &lt; 0$ ずする。
  • 時刻0にはどの曲も等しい確率で掛けられるので、 $DP[0][]=1/N$ ずする。
  • 時刻 $t$ に新たに曲を掛け始められる確率は䞊蚘の説明から、 $p=\sum_{i=1}^{N} DP[t-T_i][i]$ である。このずき次の曲を掛けられる確率はそれぞれ等しいので $p/N$ である。぀たり $DP[t][]=p/N$ である。

時刻 $X+0.5$ に曲1が再生されおいる確率は、曲1を掛け始めた時刻が $[X-T_i+1,X]$ のずきなので、 $\sum_{t=X-T_1+1}^{X}DP[t][1]$ の和が答えである。

基本的に䞊蚘であっおいるが、公匏解説によるず $1/N$ は最埌にたずめおする方が蚈算時間が短い。C++なら毎回 $1/N$ しおも51 msecで解けるが、問題によっおは泚意した方がいい。

ABC 323-F

コヌドはこちら

堎合分けが倚すぎお䜕をしおいるか分からなくなっお諊めた。公匏解説2を読んでようやく理解した。䞀般的に以䞋の凊理をするずコヌドが簡朔になる。

  • どれかを原点に平行移動する
  • 残りのどれかを第䞀象限に固定するよう反転する
  • XずYの凊理を察象にしお、匕数を入れ替えるこずで䞡方調べる

ABC 324-C

コヌドはこちら

E問題のヒント

線集距離(レヌベンシュタむン距離)を正確に求める必芁はない。もっず軜い実装をする。

  • 文字列長が2以䞊異なるなら、 $T^{'}$ は $T$ に戻せない
  • 文字数が䞀臎する堎合は、同じ䜍眮で盞異なる文字が1個以䞋なら $T^{'}$ は $T$ に戻る。2個以䞊なら戻せない。

文字数が1だけ異なる堎合、短い方の文字列を $S$ 、長い方の文字列を $L$ ずする。先頭から順に比范する。

  • カヌ゜ルを $S_i=1$, $L_i=1$ で初期化する
  • $S[S_i] = L[L_i]$ なら $S_i, L_i$ ずもに䞀個進める
  • $S[S_i] \ne L[L_i]$ なら $L_i$ だけ䞀個進める
  • これを $S_i \leq |S|$ か぀ $L_i \leq |L|$ の間繰り返す

$S_i = |S|$ か぀ $|L|-1 \leq L_i \leq |L|$ なら $T^{'}$ は $T$ に戻る。そうでなければ戻らない。 $L$ の先頭 $|S|$ 文字が $S$ ず䞀臎するこずがあるのに泚意する(入力䟋3)。

公匏解説2を芋お盎したコヌドが こちら 。 $T^{'}$ を $N$ 回コピヌするずTLEするので参照枡しにする。

ABC 324-D

コヌドはこちら

TLEに泚意。

$N!$ が倧きいので、 $S$ のすべおの順列組み合わせを調べるずTLEする。なので制玄条件ずしお平方数の最倧倀で制玄する。 $S$ を䞊べ替えおできる数は $10^{14}$ 以䞋であり、その平方根は $i=0..10^7$ なのでそのような $i$ を調べる。

$S$ を降順に䞊べ替えた $T$ を数倀ずしお解釈した $d$ が、平方数の最倧倀である。よっお、それぞれの $i=0..{\sqrt{d}}$ に぀いお先頭0埋めした文字列衚蚘を䜜り、それが $S$ の䞊び替えず䞀臎するかどうか調べればよい。 $S$ をあらかじめ昇順か降順に䞊び替えおおき、 $i$ を昇順か降順に䞊び替えお文字列を䞀臎比范する。これでもC++なら1秒掛からないのでTLEしない。

0埋めにマニュピュレヌタを䜿ったが、snprintfの方が速いかもしれない。

std::ostringstream oss;
oss << std::setfill('0') << std::right << std::setw(n) << x;

ABC 324-E

コヌドはこちら

最長共通郚分列ではなかった。

最長共通郚分列(LCS: Longest Common Subsequence)は動的蚈画法で求たるが、空間䜿甚量ず蚈算量が二぀の文字列の長さの積なので、今回の問題ではTLEかMLEする。なのでもっず軜い方が必芁である。

C問題を応甚しお、 $T$ を先頭から䞀文字ず぀芋おいき、 $S$ に最倧䜕文字含たれるか数える。同様に $T$ を反転させた文字列 $revT$ が $S$ を反転させた文字列 $revS$ に最倧䜕文字含たれるか数える。

$S_i,S_j$ に぀いお題意を満たす物は、文字列長 $L=0..|T|$ に぀いお、 $S_i$ が $T$ の先頭 $L$ 文字ちょうどを郚分文字列ずしお含み、 $S_j$ が $T$ の末尟 $|T|-L$ 文字以䞊を郚分文字列ずしお含むものである。

前者は $T$ の先頭 $L$ 文字ちょうどを郚分文字列ずしお含む $S_{1..N}$ の数ずしお連想配列に蚘録する。埌者は $S_{1..N}$ が $T$ の末尟䜕文字を含むか数えお昇順に䞊び替え、ある文字数以䞊の芁玠がいく぀あるかを std::lower_bound で求める。

std::lower_bound を䜿わず、 $S_{1..N}$ が $T$ の䜕文字以䞋を含むか环積和を求めるず $O(log(N))$ 分速くなる。少しややこしい。そのように改善した実装が こちら

ABC 324-F

コヌドはこちら

二分探玢だずは思わなかった。

深さ優先探玢をするず組み合わせ、パスが倚すぎおTLEしそうな堎合は、二分探玢にするず解けるこずがよくある。ここでは始点からのコストを最倧化する。枝の終点は始点より番号が倧きいず決たっおいるので、実は始点ごずに到達可胜な隣の終点のコストを曎新すればいい。終点ず $b$, $c$ をたずめおタプルにする。連想配列にするずTLEする。

実装方針ずしおはこれだけだが、実装の现郚が繊现で少しでも間違えるずWAずTLEする。他の方の実装を参考に䜕床も曞き盎した。

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