geam1113’s diary

主にAtcoderのコンテストの備忘録を書きます。AtCoder緑と水色を行ったり来たりしています。

AtCoder Beginner Contest 288 備忘録

コンテストページ: Toyota Programming Contest 2023 Spring Qual A(AtCoder Beginner Contest 288) - AtCoder
コンテスト中AC: A〜C
コンテスト後自力AC: D〜F

D - Range Add Query

0-indexedとします。
Xを愚直に全て0にできるか試すときどうするかを考えると、端から順に0にしていく方法が思い浮かびます。

例えば、n=8, K=3としてシミュレートしてみます。
まず、i=0を0にするため、i=0,1,2-X_0を足します。

X=\{0,\ X_1-X_0,\ X_2-X_0,\ X_3,\ \cdots \}

次はi=1,2,3-(X_1 - X_0)を足す…としたいところですが、足される項が増えてややこしいので、まず、X_0i=1,2,3に足しておきます。

X=\{0,\ X_1,\ X_2,\ X_3+X_0,\ \cdots \}

それでは先程と同様に、i=1,2,3-X_1を足し、i=2,3,4X_1を足します。

X=\{0,\ 0,\ X_2,\ X_3+X_0,\ X_4+X_1,\ \cdots \}

これを繰り返しと、最終的に以下のようになります。

X=\{0,\ \cdots ,\ 0,\ X_0+X_3+X_6,\ X_1+X_4+X_7,\ X_2+X_5+X_8\}

このようにシミュレートしてみると以下がわかります。

  • X_{i+K}X_iが足され、末尾K項にi\ mod\ Kが等しいものの累積和が構築される

最終的に末尾K項が等しい場合には、Xを0にすることが可能です。

これより、各クエリのA_{l_i},\ \cdots ,\ A_{r_i}について、mod\ Kが等しいiの累積和が全て同じかを判定すればよいです。

i\ mod\ Kが等しいものについてのAの累積和を予め計算しておけば、区間の累積和はO(1)で求められます。

よって、各クエリO(K)で判定できます。

実装: Submission #38649675 - Toyota Programming Contest 2023 Spring Qual A(AtCoder Beginner Contest 288)

E - Wish List

まず、

  • 状況が変化していき、複雑なこと
  • Nが小さいこと

から、貪欲法よりもDPっぽいなと当たりをつけます。

A_iをとることを考えたとき、iより前が何個取られているかで、どのC_iとなるか変化します。また、前に取られた個数が同じなら、どれが取られていても状況は同じなので、情報をひとまとめにできます。

ここから、以下のようなDPを考えます。
dp[i][j]:=A_iまでをj個取った時の金額の最小値

dp[i][j]を更新することを考えます。
iより前は既にj-1個取られていたとしたら、A_ii-(j-1)番目に移動しているはずなので、A_i + C_{i-j+1}の金額が必要なはず、と思ってしまいますが、これは誤りです。
なぜなら、iより前が0,1,\cdots ,j-2個のいずれかが取られた直後にA_iを取ることも可能だからです。

ここが重要なポイントで、i番目より前に0,\ 1,\ \cdots ,\ j-1個とられているような状況について、どのタイミングでA_iを取ったことにしてもよいです。

理由は直感的になりますが、まず、A_iをとるタイミングを変えてもiより前のとる順番には影響を与えません。
次に、A_iをとることで、iより後ろがずれて、とりたい位置でとれなくなってしまうのではないかと心配になります。
その場合は、先に後ろのものをとっておけば良いです。その後ろのものをとることで、その後ろより更に後ろがずれるなら、更にその後ろを先に取れば良いです。これを繰り返せば、最終的に一番後ろになるので、いつかは矛盾なくとれるはずです。

以上から、i番目まででj-1個取られている状況で、A_iを取ってj個取られている状況にする場合、かかる金額は、

A_i + min(C_{i-j+1},\ C_{i-j+2},\ \cdots ,\ C_i)

とできます。
これはSegment TreeでRMQを処理すればよいです。

以上から、DPテーブルをi=1,2,\cdots Nの順に以下のように更新できます(初期値は、dp[0][0]が0でそれ以外は\infty)。

  • A_iをとる場合
    dp[i][j] \leftarrow min(dp[i][j],\ dp[i-1][j-1]+A_i + min(C_{i-j+1},\ C_{i-j+2},\ \cdots ,\ C_i))

  • A_iをとらない場合
    dp[i][j] \leftarrow min(dp[i][j],\ dp[i-1][j])

但し、iXに含まれる場合はとらない選択をできません。

実装: Submission #38728052 - Toyota Programming Contest 2023 Spring Qual A(AtCoder Beginner Contest 288)

F - Integer Division

説明のため、乗算の×を挿入することを仕切りを挿入すると表現します。
例えば、12|3|45は、12\times 3\times 45です。

X_{j+1}\cdots X_iを10進数とみなしたものをb_{i,j}とします。これは、X_jの後ろに仕切りを入れ、その後i番目まで仕切りがない場合の10進数と捉えることができます。

i=1,2,\cdots , Nの順に見ていくとき、最後に仕切った場所が同じものについては、同じ10進数をかけることになります。

具体例を示します。X=12345として、i=5を考えたとき、最後にj=3の後ろで区切ったものを考えます。
j=3の後ろで区切った時のそれ以前の区切り方は、
123,\ 12|3,\ 1|23,\ 1|2|3の4通りとなりますが、それより後の区切りが無いためこれらには全て45が掛けられることになります。

今回は、総和を求める問題なので、以下のように解釈できます。

123\times 45 + 12\times 3 \times 45 + 1\times 23\times 45 + 1\times 2\times 3 \times 45

これを式変形すると、

(123 + 12\times 3 + 1\times 23 + 1\times 2\times 3) \times 45

カッコ内は3番目まででできる全ての区切り方の積の総和です。そこで、

a_i :=i番目までできる全ての区切り方の積の総和

とおけば、

a_3 b_{3,5}

と表現できます。

例示したXで最終的に求めたい値は、

a_5=a_0 b_{0,5}+a_1 b_{1,5}+a_2 b_{2,5}+a_3 b_{3,5}+a_4 b_{4,5}+a_5 b_{5,5}

です。なお、a_0X_1の前に区切りを入れたと考え、便宜上a_0 = 1とします。また、b_{k,k} = 0と考えます。

ところで、
a_4 = a_0 b_{0,4}+a_1 b_{1,4}+a_2 b_{2,4}+a_3 b_{3,4}+a_4 b_{4,4}

なので、

b_{0,4},\ b_{1,4},\ b_{2,4},\ b_{3,4},\ b_{4,4}

から、

b_{0,5},\ b_{1,5},\ b_{2,5},\ b_{3,5},\ b_{4,5}

に変化させることができれば、a_4からa_5を計算できます。

この方法ですが、b_{j,i-1}からb_{j,i}を計算する場合、

b_{j,i}\leftarrow b_{j,i-1}\times 10 + X_{i+1}

として計算できます。
例の場合、X_5 = 5であることから、

a_5 = a_0 (b_{0,4}\times 10+5)+a_1 (b_{1,4}\times 10+5)+a_2 (b_{2,4}\times 10+5)+a_3 (b_{3,4}\times 10 + 5)+a_4 (b_{4,4}\times 10 + 5)

式変形すると、

10(a_0 b_{0,4}+a_1 b_{1,4}+a_2 b_{2,4}+a_3 b_{3,4}+a_4 b_{4,4})+5(a_0 + a_1 + a_2 + a_3 + a_4)
=10a_4+5(a_0 + a_1 + a_2 + a_3 + a_4)

aの累積和をSとすれば、

a_5 = 10a_4 + 5S_4

となります。

一般化すると、

a_{i} = 10a_{i-1}+X_{i}S_{i-1}

となり、この漸化式を解いていけば、答えを求めることができます。

実装: Submission #38705016 - Toyota Programming Contest 2023 Spring Qual A(AtCoder Beginner Contest 288)