writer: くる / ningenMe
解説です。
- A - Omiyage
- B - Plus Or Multiple Operation
- C - Encounter On A Tree
- D - Make One With GCD
- E - LISGRID
- F - You Are A Project Manager
A - Omiyage
https://yukicoder.me/problems/2842
部分和を行い、使えるお金のうち
以下の最大値を求めます。
番目の国まで訪れて
つずつおみやげを買ったときに
円使えるかどうか。
これは計算量 で解くことができます。
writer解はこちら。
https://yukicoder.me/submissions/391792
B - Plus Or Multiple Operation
https://yukicoder.me/problems/3389
まず のときは
を作ることができません。その他の場合では必ず
を作ることができます。
進展開を考えます。
進数で
桁(0-indexed)であるとき
と書けます。
ここで倍する操作は
進数において
桁シフトする操作、
を足す操作は
桁目に
を足す操作に言い換えることができます。
よって桁の大きい方から「和の操作」によって数字を揃え、「積の操作」によって桁を上げることを貪欲に繰り返すことで、最適なコストで数を作ることができます。
ただし最初の回の操作に関しては、和の操作で起きる繰上りにより桁シフトを行うことができ、この場合の方がコストが少ないときがあります。
具体的にはと
の大小関係によってこのコストが変化します。
1クエリあたりで計算することができるため、全体として計算量
で解くことができます。
【補足】
上記の操作が最適なことに関しての補足を以下に記します。(主にテスターのtpyneriverさんが証明してくれました、ありがとうございます)
数xにする最小手順をとすると以下が成り立ちます。
(1)
(2)
(3)
のとき
が成り立つと仮定する
のとき
とすると(2)より
なる
が存在する。
またなる
が存在する。
これらよりなる
が存在する。
ここでであることと(2)より
が成立するので
が成立。
しかし(2)よりなので矛盾する。
よってで
が成り立つとき
で
が成立。
また(2)より常にであることから
となり
が成立。
以上よりが成り立つとき
が成り立ち、
より
のとき常に
が成り立つ。
(4)
で
が成立すると仮定する。
まずについて、
が
の倍数でないので(2)より
同様にで
が成立。
よってで
が成立するとき
で
が成立する。
が成立するので、
で(4)は成立する。
以上より最適手順として
と遷移がわかる。
writer解はこちら。
https://yukicoder.me/submissions/392103
C - Encounter On A Tree
https://yukicoder.me/problems/2827
「すべてのについて、頂点
の深さが頂点
の深さよりも大きいならば、頂点
に書き込まれる番号は頂点
に書き込まれる番号より大きい」という条件から深さ
の頂点に書き込まれるような数字の候補の集合を
とすると、
となります。
よってある数字が書きこまれるとき、その頂点の深さは一意に決まることが分かります。
が書き込まれた頂点の深さをそれぞれ
とし、また
が書き込まれた頂点の
(最小共通祖先)の頂点の深さを
とします。
長さのパスが存在する場合
かつ
が成り立ちます。
このようなである頂点の候補は
通りあり、その1つの
に対して
が書き込まれるような数字の候補は「
の子を根とする部分木」を考えると
通りあります。
同様にが書き込まれるような数字の候補は
通りあります。
またの子は左右の2通りがあるため、パスの長さが
となるような
の書き込み方は
通りとなります。
残りの以外の書き込み方に関しては、各深さごとに独立に候補の数字の順列を考えればよく、これは簡単に計算できます。
実装の際はとなる場合のコーナーケースに注意してください。
全体として計算量で解くことができます。
writer解はこちら。
https://yukicoder.me/submissions/392120
D - Make One With GCD
https://yukicoder.me/problems/3305
愚直に全探索をすると通りの場合があり、とても間に合いません。そこで
を行います。
から見ていって最後に
を使って最大公約数が
になるような場合の数。
ここでに関してですが、
なので愚直に状態を持つと空間計算量、時間計算量ともに制約をオーバーしてしまいます。
しかしを用いた最大公約数は必ず
の約数となり、
以下の数字の約数の個数は高々
個であることから無駄な状態を減らすことで十分高速に計算できます。
つの状態に対して遷移が
個あるので、
以下の数字の約数の個数の最大値を
とすると、計算量
で解くことができます。
writer解はこちら。
https://yukicoder.me/submissions/392116
E - LISGRID
https://yukicoder.me/problems/3092
最初に数列と
を昇順にソートします。
そして各行、各列において「前半は単調減少な数列、後半は単調増加な数列」になるように数列を構築することを考えます。ここで単調増加な部分に関しては題意の条件を満たすようにします。
するとこのとき、各マスにおける隣接マスとの大小関係が決まります。
この大小関係を有向辺とみなすことでトポロジカル順序が決まるため数字を矛盾なく書き込むことができます。トポロジカルソートしたときのスタートの候補となる頂点は最大でもの4つが存在しますが、
を最初にスタートとして
から順に書き込み、最後に
をスタートとして用いることで問題の条件に合うグリッドを構築することができます。
ソートと書き込み時の探索を考慮すると、計算量 で解くことができます。
writer解はこちら。
https://yukicoder.me/submissions/392115
F - You Are A Project Manager
https://yukicoder.me/problems/3227
を決め打ちすることを考えます。
すると左右からぞれぞれの倍数だけプログラマを選ぶ操作としてみなすことができるので、そのときの区間の中央値の塁積和を前計算しておくことで左から
チーム、右から
チーム作ったときの行動力の最大値を求める問題になります。
またこの値は塁積和をとった値に対してさらに累積maxをとることで、の分割を決める位置を探索することに言い換えれます。
と動かしたときに、中央値を求める区間の数に関しては調和級数的に状態が小さくなるため、全体で
個になります。
よってこの個の区間の中央値が分かると、
について全探索することでこの問題が解けます。
すなわち区間の大きさ、クエリ数
で区間の中央値をオフラインで答える問題に言い換えることができました。
この中央値を愚直に求めると計算量がとなりとても間に合いません。
しかし区間を平方分割し、Mo's Algorithmを利用することで区間を伸縮させながら高速に中央値を求めることができます。
区間の伸縮の際は(c++における)multisetを2本持つことで、で中央値を管理することができます。
よって必要な区間の中央値をで求めることができます。
また全体としても計算量で解くことができます。
writer解はこちら。
https://yukicoder.me/submissions/392113