目次

AtCoder Beginner Contest 205 D,E,F問題メモ

AtCoder Beginner Contest 205

D - Kth Excluded

D - Kth Excluded

これが茶Diffになるんですねえ。

問題

解法1

$A_1~A_N$ 以外の正整数を「列挙対象」とする。

各 $A_i$ から、「自身より小さい列挙対象の個数 $B_i$」を作っておく。
$A_0=0$ と便宜的に置いた上で、$A_{i-1}$ と $A_i$ の間には $A_i-A_{i-1}-1$ 個の列挙対象があるので、それを累積的に足し合わせると作れる。

$K$ をこの $B$ から二分探索することで、

がわかるので、直接求めることができる。

i    0   1  2  3  4  5  6
A   (0)  3  4  5  8 12 14
B    0   2  2  2  4  7  8

K=6 なら、
    二分探索でBへの挿入位置を求めると i=5
  →答えは A5=12 から B5-K+1=2 だけ戻った数
  →Ans = 10

解法2

解法1は事前計算によって二分探索を1発で済ませたが、こちらでは1つの $K$ につき何回か繰り返す。

まず、$A_i$ の除外がなければ、当然だが $K$ 番目の要素は $K$ になる。

$f(K)=$「$K$ 以下の $A_i$ の個数」を二分探索で求める。
$x$ 個あったら、$x$ 個分スキップされているのでその分だけ $K$ からずれ、暫定の答えは $K+x$ となる。

しかしそのスキップした $K+1~K+x$ の中にも $A_i$ が含まれているかも知れない。

最終的に $f(K+x)=x$ という均衡状態になれば $K+x$ が答えなので、この $x$ を求める。 (複数ある場合は最も小さいもの)

$x'$ が真の $x$ より小さければ $x' \lt f(K+x')$、大きければ $x' \ge f(K+x')$ となるので、 これを判定基準に二分探索を行えば、 $x$ を特定できる。

計算量は $O(Q \log{N}\log{K})$ で求められる。

解法3

本番ではこの方法で通したけど、計算量が問題ないかきちんと証明できていない。

解法2の $f(K)$ を使うところまでは同じだが、$x$ を求める際、$x←f(K+x)$ を収束するまで繰り返す。
これでも正しい答えは求まる。

こうすると、たとえば $A=(1,2,3,...,10^5)$ で、$K=1$ のとき、$10^5$ 回の処理 $f$ が1回のクエリで走ってしまう。
$f$ は二分探索を含むので、1回 $O(\log{N})$ かかる。

ただ、このように回数がかさむ $K$ は限られて、 上例のように1から隙間無く連続した $A$ に対して $f$ が走る回数は $\frac{N}{K_i}$ 回となり、 調和数列の和で、全体を通して $O(N\log{N})$ で抑えられる。

これなら $O(Q+N (\log{N})^2)$ なので間に合う。 ($K_i$ が全て異なる制約はないが、同じ $K_i$ に対してはメモ化をすればよい)

ただ、他にもっと意地悪な $A$ が無いという証明ができていない。

Python3

E - White and Black Balls

E - White and Black Balls

問題

解法

2色のボールを並べる操作は、$(0,0)$ から $(N,M)$ までのグリッド経路数の数え上げに言い換えられる。

そのうち $(K+1,0)~(N,M-K-1)$ の部分(白ボールを下方向、黒ボールを右方向とすると、左下の◣部分)を通過する経路が、条件を満たさない経路となる。

  →b
↓   0 1 2 3 4 5
w 0  . . . . . .  K=1
  1  . . . . . .
  2  x . . . . .
  3  x x . . . .
  4  x x x . . .

これを全体から除いたものが答えなのだが、重複を除くのが意外と難しい。

カタラン数

似た問題の1つに、カタラン数による経路数え上げがある。

$N \times N$ のグリッドで、対角線を超えない経路の答え(今回の問題で $H=W, K=1$ に限定したケース)は、カタラン数となる。

動的計画法で考えると、「$(0,0)$ 以降で対角線に最初に触れたのが $(i,i)$」としたときの $i$ を固定すると、そこで分割することでより小さい2つのカタラン数の和で表現できる。
これを $0~N$ まで和を取ったものが次のカタラン数となる。

ただこの方針でいこうとしても、今回は「最初に対角線(入ってはいけない境界ギリギリ)に触れた」などで分類したくても最後まで触れないルートもあるし、またその経路数が $K$ にも依存するので、DPが2次元になり、$O(WK)$ は間に合わない。

上手な発想

ナナメの直線でグリッド全体をまるっと反転させてしまうと、「元の始点→反転後の終点への経路数」が、 元のグリッドで条件を満たさない経路数と同じになる(Editorial参照)。

これは、「元の始点→最初に踏んだNG頂点→元の終点」と「元の始点→最初に踏んだNG頂点→反転後の終点」が綺麗に1対1対応することによる。

Python3

この解法を典型として覚えてしまってもいいけど、動的計画法的には解けないもんなのかな。考えたり検索したけどいまいち見つからない。

F - Grid and Tokens

F - Grid and Tokens

問題

解法

最大流。

グリッドの1行あたり・1列あたりに置ける数が限られた中で最大化、みたいな問題は、 行と列をそれぞれ $H,W$ 個の頂点とした二部マッチング問題に置きかえられることがある。

今回はそのままでは上手くいかないが、この考えの応用で解ける。

適当にコマの頂点を追加してこねくり回していたらできたけど、いまいちどうやって考えを進めればよいか、よくわからない。

コマに対応する頂点が1層だと、1つの矩形の中にコマが複数置ける場合、分身して置ける限り置くことになってしまう。

頂点を分離して容量1の辺を張ることで、複数置けたとしてもその中の1つ、ということが表現できる。

問題のアレンジとして、

Python3