SRM 548 DIV2 Hard: KingdomAndPassword
解法
oldPasswordが新しいパスワードにもなる場合がコーナーケース。
そうでない場合を考える。
先頭からi桁が等しいとする。つまり、新しいパスワードがoldPasswordと異なる最上位の桁をi(0-indexed)とする。この桁の値によって新しいパスワードがoldPasswordより大きいか小さいかが確定する。
(1)新しいパスワードのほうが大きい場合
dp[mask] = 使用した値がmaskであるときの新しいパスの最小値
(2)新しいパスワードのほうが小さい場合
dp[mask] = 使用した値がmaskであるときの新しいパスの最大値
の2種類のDPを解けば答えが求まる。
iは総当たりで固定。各iについてビットDPするので全体で
O(2^n*n^2)
ミス
1<=oldPassword<=10^16-1
なのでoldPasswordは最大16桁ある。
配列を1<<15のサイズしか確保してなかった。
SRM DIV2 Hard: OrderOfTheHats
解法
トポロジカルソートの要領で以下のビットDPを解く。
dp[mask] = トポロジカルソート済みの頂点の集合がmaskであるときの削除した辺の個数の最小値
N<=20 → ビットDP
DAG →トポロジカルソート
AtCoder AGC010 C - Cleaning
エディトリアルの判定
L>=min(max(c[i]), Σ(c[i])/2)
がよくわからなかった。
以下、条件判定の考察のみ
変数名はエディトリアルのものを踏襲
葉ではない頂点をv、
m = max(c[i])
とする。
T >= 0 (1)
は自明。
A[v]が最大になるのは
子供=>v=>親 を含む経路がすべてで
子供x=>v=>子供y (x!=y) を含む経路が1つもない場合であり、
A[v] <= Σ(c[i]) (2)
が成り立つ。
m = c[u] を満たす頂点uについて
u=>v=>x (xはvの親またはuでないvの子供)
を含む経路がc[u]個あるので
vを含む経路の数A[v]は
m<=A[v] (3)
を満たす。
逆に(1)~(3)が成り立つと仮定する。
T + (Σc[i]-T)/2 = A[v]
を整理すると
T = 2A[v] - Σc[i]
よって
L
= (Σc[i]-T)/2
= (Σc[i]-(2A[v]-Σc[i]))/2
= (2Σc[i]-2A[v])/2
= Σc[i]-A[v]
L個以上のペアが作れるかどうか判定したいのだった。
これは
ペアとならないものがH=Σc[i]-2L 個以下である
ことと同値。
H
= Σc[i]-2L
= Σc[i]-2*(Σc[i]-A[v])
= 2A[v]-Σc[i]
ここで
(2),(3)より
m<=Σ(c[i])
なので
H<=2A[v]-m (4)
ペアとならないものは
H' = m
個以下にすることができる。
vの子をc[i]の昇順に見ていく。
簡単のためi<jならばc[i]<=c[j]とする。
l個まで子を見たとき、子i<=lについてペアとならないものがc[l]個以下となるようにペアを作れる
これは帰納法で示せる。
よってすべての(k個の)子供を全部見たとき
ペアとならないものをH'個以下にできている。
H'<=H
を示す。
H-H'
= (2A[v]-m) - m
= 2(A[v]-m)
>= 2(m-m) // (3)より
= 0
∴ H>=H'
ペアとならないものをH個以下にできた。
以上から、条件判定は(1)~(3)だけでよい。
解法まとめ
根付き木にして各頂点とその親をつなぐ辺を頂点ごとに処理する。根の処理だけ特殊なので注意。
AtCoder AGC010 A - Addition
解法
偶奇だけみればいい。
操作は以下の2種類だけ。
(偶数)+(偶数) = (偶数)
(奇数)+(奇数) = (偶数)
奇数が奇数個あるとき、奇数同士を全部くっつけていっても、最後に奇数が1個に対して偶数が1個以上となり、詰む。
そうでないとき、つまり奇数が偶数個ならば、奇数同士を全部くっつけて0個以上の偶数になる。あとは、もともとの偶数ともくっつけていけばいい。
まとめなど
値は偶奇しか見なくていい。
AtCoder AGC010 B - Boxes
解法
N=1のときは明らかにYES
以下、N>=2とする。
1回の操作で合計
b=1+2+...+N = N*(N+1)/2
足される。なので
Σ(A[i])がbで割り切れないときはNOとする。
操作回数をtとすると
t = Σ(A[i])/b
ここで数列cを以下のように定める
c[i] = b[(i+1) mod n] - b[i] (0<=i<=n-1)
仮にN=5として
a[i]に
-3, -4, -5, -1, -2
の操作をしたとすると
c[i]の増減は
-1, -1, +4, -1, -1
となる。
一般化してc[i]の増減は
-1, -1, ..., +(N-1), ...,-1, -1
のように表せる。
このc[i]の増減を分解すると
-1, -1, ..., -1, -1 (①)
0, 0, ..., +N, ..., 0, 0 (②)
(②の操作は任意の1箇所で+N)
このように
①の操作と②の操作を別々にすると簡単。
数列cに①の操作をt回すると
d[i] = c[i] - t
が得られる。
あとは②の操作をdに対してt回適用して
すべて0にできればYES
まとめなど
必要条件を詰めていって、それが十分条件であることが直感的にわかればいい。階差数列の増減が単純。1回の操作を分解する。