目次

SOMPO HD プログラミングコンテスト2021(AtCoder Beginner Contest 192) D,E,F問題メモ

SOMPO HD プログラミングコンテスト2021(AtCoder Beginner Contest 192)

最近のABC、Dが伏兵なことが多い。

D - Base n

D - Base n

問題

解法

二分探索だが、コーナーケースに注意が必要。

$f(n)$ を、$X$ を $n$ 進数として解釈した後の値とする。
$X=111$ のとき、$f(2)=7$ である。

まず、$X$ が1桁の場合、1の位しかないので $f(n)$ は $n$ にかかわらず $X$ 固定である。
$X$ の値が $M$ 以下なら1通り、超過なら0通りとなる。
ここの場合分けを見落としがち(6WA)。

以下、$X$ は2桁以上とする。

$n$ が大きくなるほど $f(n)$ は大きくなる(狭義単調増加)ので、 $f(n) \le M$ が満たされる最大の $n$ を二分探索で探す。

それを $t$ とすると、$n=d+1~t$ は全て $f(n) \le M$ の条件を満たし、また $f(n)$ の値も全て異なる。

0通りの場合に注意して、$t-d$ が答え。

二分探索開始時の最小値・最大値に少し迷うところだが、、、

最小値は、$d+1$ にしてしまうとそれがそもそも不可能だった場合の区別が発生して面倒。
$X$ が $n$ 進数としてあり得ない数(ある桁に $n$ 以上の数字が含まれる)であっても、気にせず 同等の計算をして $f(n)$ を求めることは可能だし、 それでも二分探索に必要な単調増加性は崩れないので、最小値は $0$ に設定しておけばよい。

最大値については、制約上、$n$ は $X=10, M=10^{18}$ のとき最大となり、この時 $t=10^{18}$ となる。

Python3

E - Train

E - Train

問題

解法

ちょっとだけ変則的な最短経路探索。

頂点 $v$ から次の頂点へ向かう辺のコストが $v$ への到着時刻によって変わりうる(次の列車を待つ時間として表現される)。

辺のコストが時刻によって可変の場合、Dijkstra法などのアルゴリズムが使えない場合があるので、確認する必要がある。

使えない場合というのは、 「ある頂点に後から到着した方が、辺のコストが下がって、先に到着するより早く次の頂点にたどり着ける」、 つまり追い抜かされるようなことが発生する場合。

今回を考えると、待ってる間に追いつかれることはあれど、追い抜かされることは無い。 よって問題なくDijkstra法が使える。

時刻 $t$ に頂点 $v$ に着き、そこから鉄道 $i$ に乗る場合、 次の頂点に付く時刻は $ceil \left ( \dfrac{t}{K_i} \right ) \times K_i + T_i$ となるので、 これを次の頂点へのコストとすればよい。

Python3

F - Potion

F - Potion

問題

解法

ちょうどというのがポイント。

なるべく合成直後の魔力を大きくした方が待ち時間は少なくなるが、 ちょうど $X$ にならず飛び越してしまったら作れない。

合成した素材の個数 $j$ を固定してみる。

「合成した $j$ 種類の素材の合計値」と「$X$」の $\mod{j}$ が等しいとき、 しばらく待つことでちょうど魔力が $X$ のポーションを作れる。

X=93  j=10
合成直後
   43    → 53 → 63 → ... → 93

合成後、魔力は mod j が等しくなる数を小さい方から余すところなく列挙するので、いつかはXに等しくなる
逆に最初に mod j が等しくないと、Xには決してならない

よって、$\mod{j}$ が同じものの中では、合計値が大きい方が確実によい。
このあたりをまとめることで、DPが使えそう。

でも途中までは最終的な素材数がいくつになるかわからないので、とりあえずいろんな $j$ に対して求めながらDPする。

4つの添字のDPはなかなかごつい。 状態数は $N^4$ だが、まぁ $N$ が小さいのでなんとかなる。

遷移は難しくなくて、$i$ ごとに $j,k,l$ に対して以下のようにすればよい。

で、最終的に $j=1~N$ に対して $DP[N][j][j][X\%j]$ に、 $j$ 個の素材を合成したときに魔力 $X$ のポーションを作成可能な合計値の最大値が入っているので、そこから必要な待ち時間を求め、 その中の最小値が答え。

まぁ、よく考えると添字 $k$ は他の $k$ の値を使ったりしないので、外に出して $O(N^3)$ のDPを $N$ 回やってもよかったね。

Python3

枝刈りで高速化しようとするなら、できることは様々あると思うが、

というのが効果が大きそう(もちろん、$j$ が大きいうちは暫定的な答えがなかなか得られない入力も作ることができるので、絶対では無いが)