yamake's blog

主に競プロ、たまに自転車

Codeforces Round #494 A ~ Eまで

Codeforces Round #494 のバチャをしました、Bで50分かかってしまい、4完でした。

翌日にEまで解いたので、自分の方針を説明します。

 

A. Polycarp's Pockets

一番種類数の多いコインの数だけポケットがあれば必ず重複なしに振り分けられます。

C++のstd::mapを使うとO(Nlog(N))でできます。

std::unordered_mapを使うとO(N)でできます。

B. Binary String Constructing

ここはつまづいたので詳しめにいきます。

問題概要

a個の0とb個の1を並べて、s[i]!=s[i+1]となるiの数がxとなる文字列sを構成しなさい。入力のもとで、答えが必ず存在することは保証される。

解説

x \equiv \ 0\ (mod\ 2)\ \land \ a\gt bのときだけ取り上げます。

 

1. "01"\frac{x}{2}こ並べる

2. 1b-\frac{x}{2}個並べる

3. 0a-\frac{x}{2}個並べる

 

証明

1. で並べた文字のうち、最後の一つを除いたx-1文字はs[i]!=s[i+1]を満たす。

x \equiv \ 0\ (mod\ 2)\ \land \ a\gt bのとき

a-\frac{x}{2} \gt 0が言えるので必ず3. で0を配置でき、

3. で0を並べる前の数列の最後の数字は必ず1であり、

一つ後ろに0が来ることでs[i]!=s[i+1]を満たすようになる。

以上より、s[i]!=s[i+1]を満たすiの数がx個になる。

 

 a\leq bの時は10を入れ替えて同じことをしてください。

xが奇数の時は2. と3. を入れ替えて操作を行ってください。(このとき\frac{x}{2}は切り捨ててください。)

C. Intense Heat

あらかじめa[i]の累積和を取っておくと、任意の区間での\Sigma a[i]O(1)で取得できます。

k \leq x \leq nとなる長さxの区間それぞれの平均値の最大値を求めれば良いです(読解が一番時間がかかりました)。

D. Coins and Querys

全てのa[i]について、log_2(a[i])を計算し、その数を配列などに保持します。

与えられるb[j]について、b[j]にたっているフラグを上から見ていき、取れるコインから取っていきます。

取りきれなかったフラグの分は変数remなどに入れて管理します。

j0まで進んだ時にrem=0であれば取ったコインの数を出力し、そうでなければ-1を出力します。

 

E. Tree Constructing

n \leq dのとき、明らかに構築できません。

また、k=1のとき、n=2 \land d=1以外の場合構築できません。

これら以外の場合について考えます。

 

f:id:yamakeeee:20200922151514p:plain

n=11の3分木

まず、与えられた頂点数nでのk分木を考えます。

このときの直径が与えられた条件下で実現できる最小の直径になるので、この木の直径がdより大きかったら答えは"NO"です。

 

 次に、直径となるパス上の頂点に印をつけます。

f:id:yamakeeee:20200922151922p:plain

直径の端点を根とする木を再構築します。

f:id:yamakeeee:20200922152126p:plain

ここまでで"NO"を出力していないのなら、木の直径を増やしていけばいつかは条件を満たします。

この木の直径がdと一致するまで、色の付いていない頂点を色の付いている葉に接続することを繰り返したら終わりです。

 

editorial解は最初に直径d、頂点数d+1の木を作り、条件を満たしつつ残りの頂点を木に接続していくという方針でした。

たぶんeditorial解の方が実装が楽です。