2020年10月30日金曜日

dwangoプログラミングコンテスト D - タクシー

dwangoプログラミングコンテスト D - タクシー

最小費用流なので、とりあえずグラフを二周くらいしながら需要と供給を解消していって、循環流になおす。あとは負閉路を解消すれば最適になるが、このグラフ上の負閉路は環状線を一周するものしかありえないので、ここにできるだけ流せばよい。具体的には、残余グラフ上の負辺を集めて()(上限流量、辺の重み)を上限流量の昇順でソートして、先頭から順に(一周のコストが負である限り)上限流量いっぱいに流すことを繰り返した。

2020年10月23日金曜日

ARC 093 E - Bichrome Spanning Tree

XXがMSTの重みの総和より小さい場合は実現不可能である。

XXがMSTの重みの総和に等しい場合、MSTを作れるような塗り方を数えればよい……が、そもそも、だいたいの塗り方においてMSTが作れるように見える。というのも、MSTに使える辺が全部白または全部黒になっているような塗り方を除けばMSTができるからだ。つまり、MSTに使われうる辺がKK本あるとき、KK本全部を一色で塗る22MK2\cdot 2^{M-K}通りの塗り方以外はMSTを作れる。あとはKKが求まればよい。これは最小全域木TTを作った後、MM本の辺e=(u,v)e = (u, v)について最適性条件を満たせるか判定すれば数えられる。具体的には、eeの重みが(TT上の)パスuvu - v上の重みのmax\max以下であればeeはMSTに使える[1]。変更がないので、max\maxクエリはダブリング等で処理できる。(制約をN=105N=10^5と勘違いしていた。愚直でよい。)

XXがMSTの重みの総和より大きい場合、MSTに使われうる辺は全部白または全部黒に塗られていなければならないので、とりあえず白に塗られているとする。この時、黒に塗られていてMSTに使えない辺が全域木に少なくとも1本含まれていなければならないが、その1本以外は白い辺も自由に選べる。したがって、MSTに対して辺を挿入してそれによってできたサイクルから別の最大辺を削除して全域木を作った時に、重みの総和がXXになるものを考えればよい。これにはやはり木上のmax\maxクエリで答えられる。「MSTの辺と交換した時の重みの総和」がXXになる辺をpp本、XXより大きくなる辺をqq本としたとき、pp本から少なくとも一つを黒い辺にする必要があって、qq本は好きにぬってよいので、塗り方は(2p1)2q(2^p-1)2^q通り。白の分と黒の分を足すと2(2p1)2q2\cdot(2^p-1)2^q通りとなる。O((M+N)logN){O}((M+N)\log N)


厳密な証明がよくわからなかった。


  1. path optimality condition ↩︎

2020年10月17日土曜日

ABC 180 F - Unbranched

「最大サイズがちょうどLL」の代わりに、f(n,m,l):=f(n, m, l) :=連結成分のサイズがllを超えないnn頂点mm辺のグラフの数、を数えることにして、f(N,M,L)f(N,M,L1)f(N, M, L)-f(N, M, L-1)を答えとすればよい。

次数2以下の連結成分はパスかサイクルしかないので、この2つを作りながら数えていくDPができそうだが、頂点の順番をどうするかが問題になる。順番を固定した上で最後に定数を掛けるのはうまくいかなそうだし、固定せずに挿入していくDPもサイズの上限に関する制約を扱うのが困難に見える。

こういう時の典型テクニックの一つとして、「選ぶ頂点の一つは、残っているものの中でもっとも小さい番号とする」というルールを追加してグループ(この場合は連結成分)を作っていくというものがある。この場合はこれがうまくいきそうだ。

dp[x][y]:=\operatorname{dp}[x][y] :=頂点をxx個、辺をyy個使ってできる(条件を満たす)グラフの総数

とする。残ったNxN-x個の頂点からサイズssのパスグラフを作る時、連結成分のうちの1つの頂点は残った頂点の中でもっとも番号の小さいものと決めているので、残りはNx1N-x-1個からs1s-1個を選ぶことになる。ラベル付きパスグラフの総数はs!/2s!/2(ただしs=1s=1の場合は例外)なので、

dp[x+s][x+s1]+=s!2(Nx1s1)dp[x][y] \operatorname{dp}[x+s][x+s-1] \mathrel{{+}{=}} \frac{s!}{2} \binom{N-x-1}{s-1} \operatorname{dp}[x][y]

と遷移できる。サイクルを作る場合も同様で、ラベル付きサイクルグラフの総数は(s1)!/2(s-1)!/2(ただしs2s\le 2の場合は例外)なので、

dp[x+s][x+s1]+=(s1)!2(Nx1s1)dp[x][y] \operatorname{dp}[x+s][x+s-1] \mathrel{{+}{=}} \frac{(s-1)!}{2} \binom{N-x-1}{s-1} \operatorname{dp}[x][y]

と遷移する。ただし、自己ループであるs=1s=1は許されないことに注意。

2020年10月12日月曜日

CodeChef October Challenge 2020 - Compress all Subsegments

区間IIに関するffの値は、(Ai)iI(A_i)_{i \in I}中のhighest set bitの位置をkkとして、kkが立っている数が(Ai)iI(A_i)_{i \in I}に何個含まれるかでだいたい決まる:

  1. kkが立っている数が1個でそれ以外が0個の場合、その数自身になる
  2. kkが立っている数が奇数個の場合、上の場合を除いて2k2^kになる
  3. kkが立っている数が2個でそれ以外が0個の場合、不定
  4. kkが立っている数が2個でそれ以外が1個の場合、不定
  5. kkが立っている数が2個でそれ以外が2個以上の場合、0にできる
  6. kkが立っている数が4個でそれ以外が00個の場合、不定
  7. kkが立っている数が4個でそれ以外が11個以上の場合、0にできる
  8. kkが立っている数が6個以上の偶数の場合、それ以外が何個でも0にできる

まずは、kkが立っている数が偶数個の時に常はffの値が0になり、kkが立っている数が奇数個の時は常に2k2^kになるとして、偶奇のみに注目して計算する。そして、後から3, 4, 6のパターンを別に数えて補正する。

前半パートは、i=1,2,...,Ni = 1, 2, ..., Nについてそれぞれ区間[1,i],[2,i],...,[i,i][1, i], [2, i], ..., [i, i]に関する結果の和を求めるとよい。この際、

  • odd[x]:=\operatorname{odd}[x] := highest set bitがxxで、xxが立っている数を奇数個含むような区間の数
  • even[x]:=\operatorname{even}[x] := highest set bitがxxで、xxが立っている数を偶数個含むような区間の数

を保持しながら走査するとまとめて計算できる。O(NlogmaxAi){O}(N\log \max A_i)