Processing math: 48%

目次

Toyota Programming Contest 2023 Spring Qual A(AtCoder Beginner Contest 288)E,F,G問題メモ

Toyota Programming Contest 2023 Spring Qual A(AtCoder Beginner Contest 288)

オンサイト予選を兼ねるからか、問題が少し難しめ。参加者も多め?

飛ばしたEの見切りをもう少し速くできてれば、G通ってたので、惜しかったね。
まぁ、次頑張ろう。

E - Wish List

E - Wish List

問題

解法

ダルマ落としをイメージすれば、とりあえず題意はつかみやすい。
抜いた本体のコストと、高さに応じたコストがかかる。

i を必ず買うとき、 Ai+Ci をそのまま支払うよりも、自分より番号の小さい商品を k 個買ってから Ai+Cik を支払う方が、 必要ない商品の購入コストを含めても安くなることがある。

i:  1  2  3  4  5    [ ]: 必ず買う
A:  3  1 [4] 1  5    そのまま 4+6=10 で買うより、
C:  9  2  6  5  3    i=2の商品を買ってからの方が (1+2)+(4+2)=9 で安い

だがそのような商品が複数ある場合、タイミングを逃すと安くない Cj になってしまったりして、 買う順番も大事なため、どこから考えればよいかが難しい。

i:  1  2  3  4  5
A:  3  1 [4] 1 [5]   先にi=3を買うと、i=5はCjが5や6の時に買うことになってしまう
C:  9  2  6  5  3    先にi=5を買うと、Cjは3の時に買えて、その方が安い

ここで、各商品は、

よって、以下のように考えれば、買う順番を無視できる。

よって、以下のDPで O(N2) で求めていくことができる。

Python3

F - Integer Division

F - Integer Division

問題

解法

直前にどこで切ったか、みたいなDPはすぐ考えつくが、O(N^2) であり、制約がそれを許してくれない。

なので、前にどこで切ったかを気にしなくても上手くまとめられるんだろうと考察を進める。

X の先頭から i 桁目までで問題を解いたときの答えを Ans_i とし、Ans_{1} から順に求めていく。
Ans_{i-1} まで求まっていて、今から Ans_{i} を求めるとき、i 番目の桁の数字を X_i として

の2通りでざっくり分けることができる。

            Xi
   234   ← 5

① 234    * 5
① 23*4   * 5
① 2*34   * 5
① 2*3*4  * 5
②       2345
② 2   *  345
② 23  *   45
② 2*3 *   45

このうち、①に関してはすぐわかる。Ans_{i-1} \times X_i である。

問題は②の方で、なんとなく Ans_{i-1} を10倍してから X_i を足せばよさげ、、、 だが、その前にどこで切れたかによって、X_i 自身に係数 2 がかかったり 23 がかかったりする。

②       2345 →  (  234*10) +   1*5
② 2   *  345 →  ( 2*34*10) +   2*5
② 23  *   45 →  ( 23*4*10) +  23*5
② 2*3 *   45 →  (2*3*4*10) + 2*3*5

この係数はどこから来た? と考えると、Ans_{i-2} 以前の答えの累積和となっている。

なので、それも Acc_i として管理してやれば、

で計算できる。ただし最初は Ans_{i-1}=0,Acc_{i-2}=1 としておく。

Python3

G - 3^N Minesweeper

G - 3^N Minesweeper

問題

問題の理解が難しい。

解法

次元を1つ小さい問題に再帰的に分割できる。

3次元から2次元を考えると、

000 が示す範囲: 000, 001, 010, 011, 100, 101, 110, 111
                (左,手前,下  の2x2x2の立方体)
                
100 が示す範囲: 000, 001, 010, 011, 100, 101, 110, 111, 200, 201, 210, 211
                (左,手前,全体の2x2x3の直方体)
                
差分          : 200, 201, 210, 211
                (左,手前,上  の2x2x1の直方体)

このように、000 と 100 の示す範囲の差分は、 「一番上の層だけで考えたときの、200の示す範囲」となる。

つまり、(Aの添字を3進法で表して)A_{100}-A_{000} は、一番上の層だけを2次元で解く問題における A_{00}(元 200 の位置)の値となる。

これは他も同じく、A_{1xx}-A_{0xx} は、一番上の層を2次元で考えたときの A_{xx} となる。 (xx = 00~22)

同様に、A_{1xx}-A_{2xx} は一番下の層を2次元で考えたときの A_{xx} となる。

真ん中の層は、A_{0xx}+A_{2xx}-A_{1xx} が分割問題の A_{xx} となる。

このように、3次元の問題を、3層の2次元の問題に分割できた。

もっと次元が高い状態であっても、同様に 0xx...x,1xx...x,2xx...x を3つの xx...x の問題に分割することができる。

0次元まで分割したら、そのマスが 1 か 0 かがそのまま地雷のあるなしになる。
(正しい解があることは保証されているので、必ず 0 か 1 になる)

一例を示せと言いつつ実は一意に決まるやつ。

Python3