-
Notifications
You must be signed in to change notification settings - Fork 0
AGC lessons learned1
ABC 6,8問体制(126..最新)のD問題をだいたい解いたので、AGCを解いてみます。AGCにも灰diffがあります。
コードはこちら
丁寧に場合分けする
-
$0 < a \leq b$ なら積は正 -
$a \leq b < 0$ なら、a以上b以下の整数の数$b-a+1$ が偶数個なら積は正、奇数個なら積は負 - 上記以外、つまり
$a \leq 0 \leq b$ なら積は0
コードはこちら
丁寧にシミュレーションする
不確定なのは赤白どちらのボールを渡すかであって、それぞれの箱に何個ボールがあるかは決定的である。よって操作 1..M
を順番に実行して、箱に赤いボールがあるかもしれない、もしくはそうではない(箱が空か、白いボールしかない)かを伝搬する。
- 箱
$X$ に赤いボールがあるかもしれないなら、操作後の箱$Y$ も赤いボールがあるかもしれない - 箱
$X$ に赤いボールがなければ、操作後の箱$Y$ に赤いボールがあるかどうかは変わらない - 操作後に箱
$X$ が空になったら、箱$X$ に赤いボールは無くなる - 操作後に箱
$X$ が空でなければ、箱$X$ に赤いボールがあるかどうかは変わらない
コードはこちら
逆から考える。
短いロープから順に結合して、最後に
隣り合う2本ロープを結合して長さ Impossible
である。
そうでなければ答えは Possible
である。隣り合う2本ロープを結合したときの長さが
キューから最も長さが短いロープの組
-
$(p,p+1)$ を結合済なら何もしない -
$(p,p+1)$ を未結合なら結合する。ロープの組は一まとまりの区間$[l,..p,p+1,..r]$ を成すので、左右の区間と結合することを候補としてキューに載せる。-
$l > 1$ なら$l-1$ を含む区間$[a,l-1]$ ,$[l,r]$ を結合するように、候補$(l-1,l)$ をキューに載せる。 -
$r < N$ なら$r+1$ を含む区間$[l,r]$ ,$[r+1,b]$ , を結合するように候補$(r,r+1)$ をキューに載せる
-
ロープを結合済かどうかは、union-find木で管理する。あるロープにどのロープを結合したかは、ロープの代表元に std::set<Num>
で持たせて、結合しているロープの最小値と最大値と長さが分かる。ロープを結合したとき、要素数の少ない方を要素数の多い方にマージして、結合したロープの代表元に関連付ける。
これを
公式解説を読むと、優先度キューを使うまでもなく、隣り合う2本ロープを結合したときの長さが
コードはこちら
東西のうち、一方に0回、他方に1回以上移動するなら逆方向に打ち消し合うことができないので家に戻れない。南北も同様である。
コードはこちら
GreedyではWAすると思ったのだが。
DPが正解である。
上記の操作
公式解説はgreedyである。視点が違った。実装は こちら 。
コードはこちら
最初に
コードはこちら
最小の断面
偶数長の辺があればそこで切れば差は0になる。すべての辺が奇数長なら、最も小さい断面積(x1)が答えである。
コードはこちら
括弧
S,T
を (,)
、さらに 1,-1
だと思えば典型問題である。括弧の対応が取れないつまり累積して0未満なら削除できず、そうでないところの区間を削除できる。
Rubyで再帰正規表現を使うと部分点が獲れる。
p gets.chomp.gsub(/(S(?:\g<-1>)*T)/, "").size
コードはこちら
総当たり
コードはこちら
実験して法則性を見いだす。
-
$X = N$ なら$1..(2N-1)$ が解の一つである -
$X = 1$ 解なしである -
$1 < X < N$ なら、左から順に中央まで$N, N-1, ..., X+1, 1, 2, ... , X$ 、中央から右端まで$N+1, ... , (2N-1)$ である
コードはこちら
やはり総当たり
右または下への移動しかできないなら、そのような移動の総当たりを求める。この組み合わせの数は Possible
、そうでなければ Impossible
である。
公式解説を読むと、「問題文および
コードはこちら
コードはこちら
対称性が無い
コードはこちら
非対称
ボタン
ボタン
コードはこちら
トーナメントの決勝を根、初戦を葉として、根から葉までの深さを距離と定義する。題意を満たすつまりトーナメント木全体の深さを最小にするには、深い部分木を浅い頂点につなげればよい。これはDFSで求まる。
今DFSで注目している人を
-
$p$ に直接負けた人の集合を$S$ とする。$l \in S$ それぞれについて、部分木の高さを$H_l$ とする。 -
$H_i$ を降順に並べる。$i = 1..|S|$ について、$min(i + H_i)$ が、$p$ に関する部分木で深さ最小のものである。 -
$H_i$ は、$i$ 自身の部分木の高さに、根から$p$ までの高さ$t$ を加えたものである。よってDFSの呼び出しを$DFS(l, t)$ として、$t + H(l)$ を返す。特に最初の呼び出しは$DFS(1,0)$ で、その返り値が問題の答えである。
コードはこちら
偶数+偶数は偶数、奇数+奇数も偶数、したがって偶数はいくつあっても1個に縮約でき、偶数個の奇数は偶数に縮約できる。奇数+偶数、奇数+偶数は奇数なので奇数の数を減らすことはできない。よって奇数が奇数個あったら NO
、偶数個あったら YES
である。
公式解説では、すべての数の和が奇数と表現している。確かにその方が判定が速い。
コードはこちら
Greedy
-
$T_1 + K$ までに$C+1$ 人集まらなければ出発する。その次の人について同様に、$T_1$ と同様にバスを手配する。 -
$T_1 + K$ までに$C+1$ 人集まったら、乗り切れなかった人が到着した時刻を$T_i$ として、その人のために出発時間が$T_i + K$ のバスを手配する。$C$ 人きっちり集まった時点ではまだ手配しない。これも$T_1$ と同様である。
コードはこちら
Union-find木でマージ
std::set<std::pair<Num,Num>>
で、 生き物の大きさと色を管理する。小さい生き物同士を組み合わせた方が、そうでないより色数が増えるので、集合中最も小さい生き物2種類を合体する。
片方が他方を一方的に吸収できるなら色集合は増えない。そうでなければ双方の色集合を合併したものになる。これはUnion-find木でマージすることで表現できる。合体したら、大きさと色の代表元を再度集合に載せる。合体は最大
公式解説は大きさだけに注目して解いている。
コードはこちら
上に寄せる
コードはこちら
三方比較
本当は整数を <=>
で比較したい。間違って >
で比較してWAしてしまった。増減方向が変わったら区切ればよい。それより速く区切っても区切る回数は同じか増えるだけである。
- 初期値の方向は0(横這い)とする
-
$A_{i} = A_{i+1}$ なら方向を変えない -
$A_{i} < A_{i+1}$ は増加で1、$A_{i} > A_{i+1}$ は減少で-1とする - 方向が変わる、つまりこれまでの方向と
$A_{i},A_{i+1}$ の方向(1,-1)の積が負なら、区切りを一個足して方向を0(横這い)にする
コードはこちら
やってみる
実際にやってみると回数が分かる。問題は無限に続くときいつ打ち切るかである。
公式解説によれば、クッキーの個数の最大と最小の差が、一操作ごとに半分になると書いてある。そうだったのか。
コードはこちら
オイラーツアー
木をオイラーツアーして頂点番号を
すべてのクエリ NO
、そうでなければ答えは YES
である。
公式解説ではオイラーツアーとは明言していないが、LCAを考慮しているので実質的に上記と同じである。
コードはこちら
場合分けが大変
-
$A > B$ なら0通り -
$A = B$ または$A < B \land n = 2$ なら1通り -
$A < B \land n = 1$ なら0通り - それ以外なら
$1 + (b - a)(n - 2)$ 通り
コードはこちら
端まで行く
直行できなければ最上階か最下階まで行けばいいので、エレベーターに乗る回数は1回または2回である。2回乗るのは、行きたい方向にボタンがないときである。よって
- ボタンが
U
なら今より下の階$i-1$ 通り - ボタンが
D
なら今より上の階$N-i$ 通り
は2回乗る。
コードはこちら
決め打ち
最後の文字列は、
すべての
コードはこちら
徹底して理詰め。
N匹の猫が被っている帽子の色の種類数はちょうど
-
$C_i$ の帽子をかぶっている猫が猫$i$ 以外にいれば$a_i = K$ -
$C_i$ の帽子をかぶっている猫が猫$i$ 以外にいなければ$a_i = K - 1$
である。よって No
である。このことは
No
である。
No
である(これは下記とまとめる)。
同じ色の帽子をかぶった他の猫がいる No
である。
公式解説はaloneな猫という表現で、上記と同じことを述べている。
コードはこちら
パリティ
偶数な
公式解説はもっとエレガントである。そういえば出力例4は2のべき乗である。
コードはこちら
足し引きについて対称なので、最初に正規化する。つまり
最初に、 YES
、そうでなければ NO
である。以下
YES
である。
これらの区間のいずれかに YES
、そうでなければ NO
である。計算量は区間の数で決まり
コードはこちら
最大公約数
POSSIBLE
である。
なんとなく予想できた通り、公式解説は
コードはこちら
まさかgreedyが通るとは思わなかった。
何の制約もないときの一番人気のスポーツ std::set<std::pair<Num,Num>>
に
コードはこちら
単価で並べる
まず買う量を0.25リットル単位にする。これは量をすべて4倍にすればよい。
量が増えるなら単位量あたりの価格が安くなければ意味が無い。そうなるようにボトルを、2リットル当たり価格、ボトルの価格、ボトルの量、というタプルで表現する。最初はボトルを量の昇順で並べ、2リットル当たり価格が単調増加にならないようなボトルを取り除く。
こうすると量が増えるなら単位量あたりの価格が安くなる。後は量の多いボトルから順に買えるだけ買って、端数はより量が少ないボトルを買う、と言うのを繰り返す。
コードはこちら
Manacher's Algorithm だと思ったら全然違った。
コードはこちら
不変量
アリスとボリスが両方動けるなら、
これが成り立たないのは一方が端に追い込まれたときである。アリスが先手なので、
-
$A-B$ が偶数なら差を1にしたところでボリスは動けなくて負ける。アリスはボリスの方に向かっていき、端に追い込めばいい。 -
$A-B$ が奇数なら差を1にしたところでアリスは動けなくて負ける。ボリスはアリスの方に向かっていき、端に追い込めばいい。
コードはこちら
入力例を見直す
入力例2 9995
に対する 9989
は正しい例だが、並び替えた 8999
の方が素直である。つまり右側(trailing)に9をできるだけ寄せて、最上位桁は9以外でも仕方がない、という例を作ればよい。
-
$N < 10$ つまり一桁なら$N$ そのものが答えになる -
$N=d9...9$ つまり最上位桁を除いて9が続くなら、$N$ そのものが答えになる。これ以上各桁の和を増やす余地はない。 - そうでなければ
$N=a:b..c$ を$(a-1):9..9$ に置き換えればよい。$a=1$ なら最上位桁が0になるがそれで構わない。
最上位桁以外は9が並ぶというのが、意外と実装が大変である。
コードはこちら
最後が2でなければ解なしである。これを忘れてWAした。
-
$newmin(N) = A_i \lceil min(N) / A_i \rceil$ つまり$\lfloor newmin(N) / A_i \rfloor$ が$min(N)$ となる最小値 -
$newmax(N) = A_i (1 + \lfloor max(N) / A_i \rfloor) - 1$ つまり$\lfloor newmax(N) / A_i \rfloor$ が$max(N)$ となる最大値
で更新する。
コードはこちら
辞書順なら並べ替え
std::next_permutation
で std::next_permutation
はfalseを返すので分かる。
偶数を3の倍数個、3の倍数だが偶数ではない数を偶数個並べる。そうすれば、2の倍数の数からみると他の数の和は偶数である(偶数は単独で偶数、3の倍数は2個ずつ組み合わせると偶数)、3の倍数の数からみると他の数の和は3の倍数である(3の倍数は単独で、偶数を3個ずつ組み合わせる)。この組を
30000を超えない範囲で偶数を3の倍数個、3の倍数だが偶数ではない数を偶数個並べる。最初に偶数を6個単位で並べ、30000を超えたら3の倍数だが偶数ではない数を並べる。
6個単位でならべて
境界例をコードに書くのは難しいのでハードコーディングする。
コードはこちら
累積和
std::lower_bound
で求めて足すと答えが求まる。
公式解説はこれを一歩推し進めて、累積和が等しい数の組から答えを導出している。
コードはこちら
元々の盤面の対角線
マス
よって対角線をずらす量を
コードはこちら
手を動かす
実際に操作すると、
コードはこちら
色々考えたが諦めた。
最後に思いついたのがLISだったのだが、もう一歩だった。
-
$Q_{i-1} < Q_{i}$ なら$L_i = L_{i-1} + 1$ -
$Q_{i-1} > Q_{i}$ なら$L_i = 1$
コードはこちら
-1
である。そうでない場合を考える。
丁寧に場合分けする。いま注目する
- 隣からは1より多く増やせないので、
$A_{i} - A_{i-1} > 1$ なら答えは-1
である。 - 隣から1増やす操作は一回でできるので、
$A_{i} - A_{i-1} = 1$ なら操作回数を1増やす。 - 隣と同じかそれより低い場合
$A_{i} - A_{i-1} < 1$ は、$h = A_i$ にするため左から順に$1,2,..h$ と積み上げる必要があるので操作回数を$h$ 増やす。
コードはこちら
総当たり
公式解説は、
コードはこちら
やはり総当たり
この問題は
拡張GCDを持ち出したが使い道が無く、単に解答時間の無駄だった。
コードはこちら
ランレングス
同じ色のスライムが
センチネルを使うと左右の端のスライムを特別扱いしなくて済む。左端に色
コードはこちら
Greedy
- 全員にお菓子をきっちり配る、つまり
$sum(a) = N$ なら答えは$N$ である。そうでなければ以下。 - 累積和を
std::upper_bound
して、累積和が$X$ を超える最初の子供が$1 \leq i \leq N$ 人目なら、$i-1$ 人までは喜ばすことができ、$i$ 人目以降を喜ばせることはできない。余ったお菓子を$N$ 人目の子供に全部配れば(公式解説の表現だと押し付ける)、$N$ 人目の子供は喜ばないが他の子供は喜ぶ可能性がある。よって答えは$min(N-1, i-1)$ である。
コードはこちら
条件がややこしい
解があるなら
-
$N=M$ なら、$S=T$ のとき解は$N$ 、そうでなければ解なし-1
である -
$S,T$ の最初の文字が異なるなら解なしである -
$N$ が$M$ で割り切れるもしくは$M$ が$N$ で割り切れるとき、$S,T$ の最後の文字が異なるなら解なしである -
$N,M$ が互いに素なら、$S,T$ の文字を互い違いに$X$ に組み込めるので解がある - それ以外は実際に
$X$ を作ってみる。上記のフィルタリングなしに$X$ を作るとRE/MLEする。
コードはこちら
やってみる
白石の左に黒石が並んでいれば、並んでいる黒石の左端にその白石を置ける。並んでいないつまり左が白石なら何もできない。よって、既知の黒石の場所をカーソルとして覚えて置き、白石を左に寄せていく。
- 初期状態ではカーソル
$c$ は$NA$ -
$S_i=B$ かつカーソル$c=NA$ なら、カーソルを$i$ にする。 -
$S_i=B$ かつカーソル$c \ne NA$ ならば何もしない -
$S_i=W$ かつカーソル$c=NA$ なら何もしない -
$S_i=W$ かつカーソル$c \ne NA$ なら$i-c$ を操作回数に加算する
公式解説は上記を上手く整理していて、白石の左にある黒石の数であることを導出している。
コードはこちら
実はgreedyで解ける。
大きな数字は相手のペアが自分以下の数字に限られるが、小さな数字は相手のペアが自分以上なら何でもいいので使い勝手がいいと分かる。よって大きな数字から順にペアを組む。
重複を許して大きな数字
-
$A$ が2のべき乗、つまり立っているビットが1個なら、もう一個$A$ を組めるなら組ませる。 -
$A$ が2のべき乗以外なら、$A$ のビット幅が$w$ として$2^w-A$ と組めるなら組ませる - ペアを組めたかどうかにかかわらず、
$A$ を1個削除する。ペアを組めたらなら組んだ相手を削除する。
こうするといつかボールが尽きるので答えが求まる。
コードはこちら
一つ多い
解毒できる回数は +1
をうっかり忘れやすい。それとは独立にクッキーBは食べたいだけ食べればいいので、答えは
コードはこちら
文字 a..z
について掛けたものから1引く(空文字列なので)と答えである。
コードはこちら
制約からDPだと思った。
std::lower_bound
から分かる。
- このような
$j$ がなければ塗れない。$DP[i] = DP[i-1]$ である。 -
$j = i-1$ なら塗っても何も変わらない。$DP[i] = DP[i-1]$ である。 -
$j < i-1$ なら塗らないときと塗ったときの両方を考慮して、$DP[i] = DP[i-1] + DP[j]$ である。
コードはこちら
後ろから再帰
順操作 -1
である。
定位置にある
逆操作を繰り返して空集合にできたなら、この逆操作の逆順が順操作の順番つまり答えである。途中で定位置の -1
である。
コードはこちら
手を動かす
とても時間が掛かったが、手を動かすと状況が見えてくる。例えば
-
$1,N$ と結ぶ -
$i \ne j, \bar{i} \ne j$ なら$(j,N+1-j)$ と結ぶ
-
$1,N-1,N$ と結ぶ -
$i \ne j, \bar{i} \ne j$ なら$(j,N-j)$ と結ぶ
辺が重複するので並び替えてから std::unique, std::erase
で重複を除いてから出力する。
公式解説はもっと簡潔に説明していて、奇数のときは
コードはこちら
BFSで求まる。開始点は距離0で初期化することを忘れない。
コードはこちら
Greedyだと1 WAが取れないまま諦めた。
正しくは最終状態から考える。こちらの 記事 通りに実装したが、有効な区間は
コードはこちら
どこで追い越すか
最初に
追い越し可能かどうかは、以下の三パターンを調べる。1,2,3をすべて満たすなら追い越し可能ではなく、操作は達成不可能である。
- Bで追い越す。つまり
$B+1$ は岩ではなく、$B > 1$ なら$B-1$ は岩ではない - Dで追い越す。つまり
$D-1$ は岩ではない、$D < N$ なら$N+1$ は岩ではない(これがなくても AC できてしまった) - 途中で追い越せない。つまり
$[B,D]$ に何も置かれていないマス目が三連続している箇所がない
追い越し可能または追い越す必要がなければ、すぬけ君とふぬけ君が移動可能か調べればよい。これは動的計画法で1,2歩先に進めるかどうか調べ、進んだ先でも同様に調べるのを
公式解説をみると、もっと条件が簡単だった。実装すると このように になる。
-
$[A,C]$ ,$[B,D]$ に岩が二連続していない -
$C > D$ なら途中で追い越せる場所がある。つまり$[max(0,B-1),min(N,D+1)]$ に何も置かれていないマス目が三連続している箇所がある。境界値の取り方が公式解説は巧妙である。
コードはこちら
Rubyで string#scan
は思いついたが、そこから文字列置換して転倒数は思いつかなかった。
コードはこちら
ACできてしまった
問題を読み違えたのとSTLの使い方を間違ったので75分掛かった。
最初に簡単な例に対処する。 Yes
、 No
である。
No
である。あれば
最後にラクダは循環しているので、 Yes
、そうでなければ No
である。
公式解説は、
-
$0$ が循環する -
$A,A,0$ が循環する -
$A \oplus B \oplus C = 0$ なる$A,B,C$ が循環する
実装する と結構長い。
コードはこちら
頂点の一つは原点に固定する。
他の二点を選び、外積
公式解説を見たら、
コードはこちら
長考
解くのに24分掛かった。文字列の長さが違えば文字列は異なるので、文字列長は基本的に1にして、1でだめなら2にして、2の後は必ず1にすればいい。このgreedyで解ける。
- 1文字の文字列の後に1文字の文字列を置けないのは、前が1文字の文字列で、同じ文字が続いたときだけである。
- そうでなければ1文字1文字列に分割する
- 前が1文字の文字列で、同じ文字が続いたら2文字からなる文字列を作る。つまり
aaa
をa,aa
にする。 - 2文字の文字列の次は、1文字からなる文字列を作る。
aaaaaa
はa,aa,a,aa
にする。
基本的にはこれで上手くいくのだが、 aaaaa
と同じ文字が5文字続く(一般的には a,aa,a,a
を a,aaa,a
と区切り直せばよく、余った一文字を2文字の文字列と合併して3文字にすると考える。要するに最後の分割文字列をなかったことにして無視すればよい。
コードはこちら
どうして解けないのかが分からない。
コードはこちら
丁寧に場合分け
そうでないなら
ランの長さから以下の答えを求める。
-
$L=0$ のランがあるなら$K \lfloor len/2 \rfloor$ -
$R >= |S|$ つまり一周目と二周目をまたぐランがあるなら$(K-1) \lfloor len/2 \rfloor + K \lfloor (|S|+1-L)/2 \rfloor $ - それ以外は
$K \lfloor len/2 \rfloor$
コードはこちら
二部グラフの彩色問題と同じである。つまり頂点集合
色を塗れないのは、既に色が塗ってあって条件を満たさない=頂点集合の番号の差が1以外のときである。このときは探索を打ち切ってよい。
公式解説は、グラフの直径を用いてきれいに導出している。よく考えたら、上記も同じことをしている。
コードはこちら
どこかで見た気がする
<
>
初期値は <
があれば >
があれば
コードはこちら
端に押し付ける
コードはこちら
二分探索だとは分かったが、それ以上詰め切れず諦めた。
コードはこちら
01BFSっぽい。
白黒同じ色をたどって移動できるマスの組をめる。始点
始点
-
$(1,1)$ が白なら0回、黒なら1回 -
$(1,1)-(Y,X) \setminus (Y,X)$ から$(Y,X)$ に同じ色でたどれるなら0回 -
$(Y-1,X)-(Y,X)$ から1操作でマス目をよい状態にしてたどれるなら1回 -
$(Y,X-1)-(Y,X)$ から1操作でマス目をよい状態にしてたどれるなら1回
の最小値である。これをDPで求める。色が変わる回数を
公式解説はこれをもっと洗練させて、白から黒への変化回数(
コードはこちら
正N角形。
コードはこちら
コードはこちら
合同かと思ったら違った、
小数を整数部
入力を
よって加工した
コードはこちら
41分は時間掛け過ぎである。
atcoder
a
を含むなら先頭に持ってくれば操作回数はどうあれ atcoder
a
しか含まないならどうやっても atcoder
先頭から
公式解説は1,2文字目しかみていない。
コードはこちら
公式解説を読んでも理解できない。
なのでこちらの 記事 を読んで理解した。私が想定した 0
を寄せるのではなく 1
を寄せるのが正解で、余った 1
を対消滅させる方法が上手く思いつかなかった。
コードはこちら
解説を見るまで全く分からなかった。
コードはこちら
実装を間違えたらACできてしまった。
答えは 0
, 1
, 0
を並べたものである。
-
$S+S$ の$1..N$ 文字目に0
がなければ、$S+S=1..1,0..0,1..1,0..0$ と1,0
を$N$ 個連続で並べたものなので題意を満たす -
$S$ の$1 \leq i \leq 2N$ 文字目が0
で、それより前つまり$j < i$ 文字目は1
とする。このとき$[i+1,2N+i-1]$ 文字目には1
を$N$ 個含み、$[2N+i,4N]$ 文字目には0
を$N$ 個含む。
コードはこちら
実は
具体的には、
正の数ではなく非負整数というのを扱い損ねてペナルティを出してしまった。
コードはこちら
最初が肝心
-
$S$ が末尾の文字が、$S$ の先頭の文字$k$ と異なるなら、$S$ を1回で丸ごと削除できる。 -
$S$ を末尾から見ていく。$k$ と異なる箇所が連続している、つまり$k,...,(c,d),...,k$ なら、先頭から$c$ までと、$d$ から末尾までを削除する。計2回である。$c$ と$d$ は同じ文字でも構わない。 - 上記を満たさない、つまり
$k$ と異なる文字が連続しなければ、削除できない$k$ が残る。
コードはこちら
ABC, ACB, BAC, BCA, CAB, CBA を全部試せばよいのは分かるが、どう試すのかが分からなかった。前から取るとか後ろから取るとか色々試したが解けなかった。
公式解説はホールの定理に基づいて3分割する、とある。意外と実装が大変である。
コードはこちら
手を動かすと解ける。
###......
...###...
......###
###......
...###...
......###
###......
...###...
......###
#
の場所として上記から ?
を除いて *
を増やす。確かに連結成分は
###.......
...###....
......?##*
###.......
...###....
......##?*
###.......
...###....
......#?#*
......***.
#
の場所として上記から ?
を除いて *
を増やす。確かに連結成分は
###........
...###.....
.......?##*
###........
...###.....
......##.?*
###........
...###.....
......?.##*
......###..
......**.*.
公式解説1が簡潔で、公式解説2は大きさ1の成分を基に上記とは異なる微調整をしている。
コードはこちら
いかにもマルチテストケースらしく、入力例以外が全滅したかと思ったら再々提出がACした。
数
一般的に、桁数の少ない数を残すと損する。なぜなら桁数が一つ多ければ数字の候補は10倍になる、つまり
このことから、
コードはこちら
解答長が
自明な到達点として、
奇数番目が山になる、つまり
- 元々
$A_{2i-1} < A_{2i} > A_{2i+1}$ なら何もしない -
$A_{2i-1} < A_{2i} < A_{2i+1}$ なら$A_{2i} > A_{2i+1}$ になるように交換する -
$A_{2i-1} > A_{2i} > A_{2i+1}$ なら$A_{2i-1} < A_{2i}$ になるように交換する - それ以外つまり
$A_{2i-1} > A_{2i} < A_{2i+1}$ ときは、$max(A_{2i-1}, A_{2i+1})$ と$A_{2i}$ を交換する。こうすることで$i$ が小さいほど振れ幅を大きくする
公式解説1としていることは同じだが、公式解説は証明を与えている。
コードはこちら
文字の置き方をDPするのだと予想はしたが、その先が全く分からなかった。公式解説にある通り、ある連続部分文字列である文字が過半数なら、半分に切ってもどちらかでは過半数を占めている。これが分からなかった。
DPの初期化が大変である。
コードはこちら
解説を読むまで全く分からなかった。
コードはこちら
初手を考える。Aliceとしては、 A
の前に B
がなければ、 A
の前に 'B' が一文字だけあれば、
これを拡張し、 A
を取り除いているので、この時点で A
が残っていなければAliceは勝てない。言い換えれば、 A
を含んでいる必要がある。この状況で、先頭から A
までに B
が
Bobはこれと対照である。 B
を取り除いているので、この時点で B
が残っていなければBobは勝てない。言い換えれば、 B
を含んでいる必要がある。この状況で、先頭から B
までに A
が
公式解説はこれを起点にもっと証明を簡潔にしている。
コードはこちら
左右対称にしようとして解けなかった。公式解説にある通り、左側は1ずつ増やせばよい。
コードはこちら
正確な時間をはかりそこねたが、自力ACまで3時間を切ったと思う。ヒントは解くまで見ていない。
初期値として 0
、 1
を考える。最初に 1
に、それ以外を 0
にすると実現できる。 0
にする。以後、
上記を一般化して、
0
を追加して、 1
に、それ以外を 0
にすると実現できる。より正確には、 1
にし、それ以外の 0
にする。この後、
公式解説と全く同じ解き方だと思う。