2019年8月29日木曜日

CS Academy - Necromancer

CS Academy - Necromancer

複雑な設定だが、考えるべきは各投票者がどの候補者をトップ(一番目)にした可能性があるか、だけである。

与えられた投票者AAについて、AAの投票した候補者の部分列がq1,q2,...,qlq_1, q_2, ..., q_lであるとわかっているとする。ネクロマンサーの投票操作を最小で済ませるためには、候補者11にとって最善のケースを考えるべきである。q1=1q_1 = 1ならAAは候補者11をトップにしたと考えれば良いし、q1,q2,...,qlq_1, q_2, ..., q_lに候補者11が含まれていない場合もやはり候補者11をトップにしたと考えてよい。その他の場合、つまり部分列の中に11が含まれているが最初ではない場合、AA11以外の候補をトップにしたことになる。l=Kl = Kならそれはq1q_1だし、lKl \neq Kならq2,...,qlq_2, ..., q_l以外のいずれかの候補である。

さて、11以外に投票したことがわかっている候補者については、投票先を2,3,...,K2, 3, ..., Kにばらけさせて、得票数の最大値ができるだけ小さくなるようにしたい。その最小値がわかれば、ネクロマンサーはそれを超えるように候補者11の得票を増やせばよい。これは二分探索とフローで実現できる。つまり、得票数の最大値がある値DD以下にできるかどうかを最大フローで判定すればよい。

グラフの作り方としては、始点SSを(投票先が1以外の)各投票者と容量11の辺でつなぎ、投票者をありえる投票先に容量11の辺でつなぎ、(1以外の)各候補者と終点TTを容量DDの辺でつなげばよい。

サンプルのケースでは次のようなグラフになる:

Sample 1

3人の投票者v1,v2,v3v_1, v_2, v_3について、4人の候補者p1,p2,p3,p4p_1, p_2, p_3, p_4の中からありえる投票先につないでいる。何も書かれていない辺の容量は11である。候補者11は常に無視してよいし、投票者33も候補者11に投票しているとみなせるので無視してよいが、便宜上、図に書いている。
このグラフに流量22=S=Sから出ている辺の容量の合計)のフローが流せれば、得票数の最大値がDD以下にできることがわかるので、二分探索で境界を探せば良い。

2019年8月25日日曜日

ARC 071 E - TrBBnsformBBtion

ARC 071 E - TrBBnsformBBtion

まずは操作が可逆かどうか考えてみる。操作1は逆操作が可能である:

  • BB → AAB → AAAA → A
  • AA → BAA → BBBB → B

操作2は、文字列が空でない限り逆操作が可能である:

  • A → BB → AAB → ABBB
  • A → BB → BAA → BBBA
  • B → AA → BBA → BAAA
  • B → AA → ABB → AAAB

したがって、文字列の集合はいくつかの同値類に分割できそうと思える。そこで、それらをもっとも短い文字列で代表させることを考える。

  • AB → AAA → 空
  • BA → BBB → 空
  • AA → B
  • BB → A

に従うと、長さ2以上の文字列は必ず短くできる。つまり、任意の文字列は、できるだけ短い文字列に変換するとA, B, 空のいずれかになり、文字列の集合が3つの同値類に分割できるとわかる。1

3つの同値類をそれぞれA,B,OA, B, Oで表すことにして、文字をつなげる操作を++で表すと、演算の性質は以下のようになっている。

A+B=B+A=OA+A=BB+B=AA+O=O+A=AB+O=O+B=BA+B = B+A = O \\ A+A = B \\ B+B =A \\ A + O = O + A = A \\ B + O = O + B = B

これはZ/3Z{\mathbb Z}/3{\mathbb Z}と同型なので、mod  3\mod 3で文字列SSTTの累積和を取っておけば、クエリにはO(1){\mathcal O}(1)で答えられる。2


  1. 文字列 aa → 空 → 文字列 bbという変換は不可能なのが気になるが、空になる直前は必ずAAAかBBBのどちらかになっていて、AAA → BBBBBB → BBBとその逆の変換が可能なので問題ない。 ↩︎

  2. 上では、そもそも文字列A, Bと空の文字列は本当に相互変換できないのか確かめていなかった。しかし、考察をここまで進めると、文字Aを11、文字Bを22としてmod  3\mod 3で和を見れば、2種類の変換の前後で総和が変化しないことがわかり、それが証明になっている。 ↩︎

2019年8月24日土曜日

ARC 006 D - アルファベット探し

ARC 006 D - アルファベット探し

chokudaiさんのツイートより。簡単な方針を思いつけなかった……

「文字を囲む正方形」の一辺の長さが常に55の倍数になることを利用する。黒マス(i,j)(i, j)が与えられたとき、(i,j)(i, j)を基点に黒マスだけを8方向にたどるBFSをして、連結成分の上下左右の境界U,D,L,RU, D, L, Rを突き止める。DU+1=5kD-U+1 = 5kとすると拡大率がkk倍とわかるので、領域[U,D]×[L,R][U, D] \times [L, R]を左上(U,L)(U, L)を基準に1/k1/k倍に縮小する。

各点に対して上の処理を行うと、図上の文字はすべて等倍になる。あとは、図上のすべての7×77\times7の正方形について、33文字×4\times 4方向 =12= 12パターンのいずれかに一致するか調べればよい。これは例えばローリングハッシュなどでできる。1 計算量はO(HW){\mathcal O}(HW)


連結成分のサイズだけ見ればよいかもというのは最初に考えたけれど、倍数では文字を1つに絞れないと思ってすぐに捨ててしまった。(実際には、文字をkk倍に拡大すると連結成分のサイズがk2k^2倍になるので、異なる文字のサイズが重なることはない。)


  1. プログラミングコンテストチャレンジブック 第2版, pp.333-335より。でも、よく考えると等倍に戻したタイミングで愚直にパターンマッチすれば十分だった。 ↩︎

2019年8月22日木曜日

AGC 033 D - Complexity

AGC 033 D - Complexity

f(y1,x1,y2,x2):=f(y_1, x_1, y_2, x_2) := 矩形[y1,y2)×[x1,x2)[y_1, y_2) \times [x_1, x_2)の複雑度

とすれば自明な漸化式が導けるが、時間的にも空間的にも間に合っていない。そこで、次の点に注目する:

  • 複雑度は高々log2(HW)=16\lceil \log_2(HW) \rceil = 16と小さい
  • x2x_2y2y_2が増加すると複雑度は単調に増加する

したがって、ナップサックDPのように値と変数を入れ替えたDPができる。具体的には

f(y1,x1,y2,c):=f(y_1, x_1, y_2, c) := [y1,y2)×[x1,X)[y_1, y_2) \times [x_1, X)の複雑度がcc以下になるような最大のXX
g(y1,x1,x2,c):=g(y_1, x_1, x_2, c) := [y1,Y)×[x1,x2)[y_1, Y) \times [x_1, x_2)の複雑度がcc以下になるような最大のYY

としてDPする。f(y1,x1,y2,c)f(y_1, x_1, y_2, c)の漸化式を与える。左右に分割する場合に限ったXXの最大値は、複雑度c1c-1以下の2つの横に並んだ矩形についてできるだけ横幅の合計を大きくすることで達成できるので

f(y1,f(y1,x1,y2,c1),y2,c1)f(y_1, f(y_1, x_1, y_2, c-1), y_2, c-1)

また、上下に分割する場合のXXの最大値は、複雑度c1c-1以下の2つの縦に並んだ矩形を、高さの合計がy2y_2以上になるようにするという条件でできるだけ横幅を大きくすることで達成できるので

arg maxX(g(g(y1,x1,X,c1),x1,X,c1)y2)\argmax_X \bigl( g(g(y_1, x_1, X, c-1), x_1, X, c-1) \ge y_2\bigr)

となり、この2つのうちの大きいほうがf(y1,x1,y2,c)f(y_1, x_1, y_2, c)である。(後者は二分探索で得られる。) 同様に、g(y1,x1,x2,c)g(y_1, x_1, x_2, c)

g(g(y1,x1,x2,c1),x1,x2,c1))g(g(y_1, x_1, x_2, c-1), x_1, x_2, c-1))

arg maxY(f(y1,f(y1,x1,Y,c1),Y,c1)x2)\argmax_Y \bigl( f(y_1, f(y_1, x_1, Y, c-1), Y, c-1) \ge x_2 \bigr)

の大きいほうに等しい。

α:=max(H,W)\alpha := \max (H, W)とするとき、計算量はO(α3log2α){\mathcal O}(\alpha^3 \log^2 \alpha)。かなり厳しそうだが、TLが5秒なのでメモ化で一応通った。想定はボトムアップのDPで尺取り法っぽくやってO(α3logα){\mathcal O}(\alpha^3 \log \alpha)らしい。

参考:
http://drken1215.hatenablog.com/entry/2019/05/10/215400