Quantcast
Channel: プログラミング
Viewing all articles
Browse latest Browse all 7890

ABC364挑戦記(E問題まで) - JunKobayashi’s diary

$
0
0

D問題が425点の回における個人的通例から逃れられず3完。DとEについては解説を読んでも全く理解できないとは思わなかったため、今後同様の問題と出くわした場合に撃沈しないよう今回でしっかりと固めておきたい。

 

<A問題>

↓問題のページ↓

A - Glutton Takahashi

 

基本的にはsweetが2連でやって来るとダメということだが、「sweetが2連でやって来る箇所が1つもあってはならない」ではなく、「ひとたびsweetが2連でやって来るということがあれば、それ以上先は食べられない」という話であることに注意して、

\(i = 0, 1, \dots , N - 3\)について、\(S_i = S_{i + 1} = \text{sweet}\)なる\(i\)が1つでも存在すればNoを、1つも存在しなければYesを出力。

 

<B問題>

↓問題のページ↓

B - Grid Walk

 

文字列\(X\)の長さが最大で50しかないので、そのままシミュレーションするだけでAC獲得できる(最終的には1-indexedで出力する必要がある点にだけ注意)。

 

<C問題>

↓問題のページ↓

C - Minimum Glutton

 

甘さ・しょっぱさそれぞれについて、数値が大きい方から順に食っていくのが最も効率が悪く、食える個数が最小になる。というわけで、それぞれを降順ソートしてシミュレーションすると良い。甘さ・しょっぱさのどちらを優先して評価するとより食える個数が少なくなるかは入力に依存するので、それぞれについて優先した場合の結果2つを記憶しておき、それらのうち小さい方を出力する。ソートが一番重たくなるので\(\mathcal{O}(N \log N)\)の処理となる。

 

<D問題>

↓問題のページ↓

D - K-th Nearest

 

基本的に 公式解説の通りに実装するだけだが、自分用にもっと詳細に記述しておく(前提として、\(a\)を昇順ソートしているものとする)。

\(j = 0, 1, \dots , Q - 1\)について、\(b_j - d \le a_i \le b_j + d\)を満たすような\(i\)の個数について考える。これは明らかに\(d\)について広義単調増加であり、\(d\)が特定の値よりも小さい場合は\(k_j\)よりも少なく、それ以上の\(d\)では\(k_j\)個以上存在するという構造になっている。このような構造に対しては二分探索が非常に有効であるから、二分探索を用いて、\(b_j - d \le a_i \le b_j + d\)を満たすような\(i\)が\(k_j\)個以上存在するような最小の\(d\)を求める。そのためには、\(L = -1, U = 2^{60}\)とでも初期化し、\(U - L \gt 1\)が成立している限り、\(\displaystyle m = \frac{L + U}{2}\)なる\(m\)について、以下の[繰り返し部分]の処理を繰り返すのが良い(繰り返しから抜けた後の\(U\)が求めるべき\(d\)となる)。

[繰り返し部分]

\(a\)に対して二分探索を実行し、\(a_s \le b_j - m\)を満たすような最小の\(s\)および\(a_t \lt b_j + m\)を満たすような最小の\(t\)を求め、\(t - s \ge k_j\)ならば\(U\)を\(m\)で更新し、そうでなければ\(L\)を\(m\)で更新する。

[繰り返し部分終わり]

上記[繰り返し部分]の処理によって最小の\(d\)を求められたら、再度\(a\)に対して二分探索を実行し、\(a_s \le b_j - d\)を満たすような最小の\(s\)および\(a_t \lt b_j + d\)を満たすような最小の\(t\)を求める。この時、\(s, s+ 1, \dots , t - 2, t - 1\)の\((t - s)\)個が、\(b_j - d \le a_i \le b_j + d\)を満たす\(i\)である。\(t - s = k_j\)が成り立っている場合、全ての\(a_i\)のうち、\(b_j\)との距離が\(k_j\)番目に近いものというのは、換言すれば\(a_s, a_{s + 1}, \dots , a_{t - 2}, a_{t - 1}\)の\(k_j\)個のうち\(b_j\)から最も遠いものであるから、\(a_s, a_{t - 1}\)のうちどちらかである。したがって、出力すべきは\(\max(|b_j - a_s|, |b_j - a_{t - 1}|)\)であることが分かる。\(t - s \gt k_j\)の場合、\(a_s\)や\(a_{t - 1}\)が重複していることを意味しているので、結局は同じ答えとなる。

大まかに計算量を見積もると、\(a\)をソートするのに\(\mathcal{O}(N \log N)\)かかり、\(Q\)回のクエリに対して二分探索を行うので、\(R = 2^{60} + 1\)として\(\mathcal{O}(Q \log R \log N)\)くらいかかり、両者を合計しても十分間に合う。

 

<E問題>

↓問題のページ↓

E - Maximum Glutton

 

こちらも基本的には 公式解説と変わらない(キーを3つにする形式に不慣れだったとはいえ、最近は動的計画法の学習を積み上げてきてはいたので正直この問題はD問題よりも本番中にAC獲得できないとダメだったように思う)。

公式解説の最初に出てくる定義のように\(dp(i,j,k)\)を定義することができれば答えは容易に分かるが、\(N X Y \)の値が最大だと\(8 \times 10^9\)にまで上るためこの定義では上手くいかない。したがって、\(dp\)のキーと値を交換し、以下のように\(dp(i,j,k)\)を定義する。ただし、\(i, j, k\)は\(0 \le i \le N \land 0 \le j \le N \land 0 \le k \le X \)を満たすものとする。

\(dp(i, j, k) := 1, 2, \dots , i\)番目までの料理について食う・食わないを決めているという前提のもと、\(j\)品を食って甘さの合計が\(k\)となる場合のしょっぱさ合計の最小値

\(dp\)の初期条件は以下の通り。\begin{equation}
  dp(i,j,k)=
  \begin{cases}
    0 & \text{if $(i=0 \land j=0 \land k=0) $,} \\
    \infty & \text{otherwise} \\
  \end{cases}
\end{equation}また、\(i = 0, 1, \dots , N - 1; j = 0, 1, \dots , N ; k = 0, 1, \dots , X\)について、\(dp\)の遷移を考える。\((i + 1)\)番目の料理を食わない場合は、\(dp(i + 1, j, k)\)を\(dp(i , j, k)\)で緩和することになる。\((i + 1)\)番目の料理を食う場合は、\(dp(i + 1, j + 1, k + A_i)\)を\(dp(i , j, k) + B_i\)で緩和することになる(ただし、\(j \lt N \land k + A_i \le X\)でないと食う方向の遷移はできない点に注意)。このようにして遷移させていった\(dp\)に対し、\(j = N, N - 1, \dots , 0 ; k = 0, 1, \dots , X\)という方向で順に\(dp(N, j ,k)\)の値を見ていき、\(dp(N, j ,k) \le Y\)なる\(k\)が見つかれば、\(\min(N, j + 1)\)の値を出力すると良い(A問題と同様、甘さ・しょっぱさの合計がそれぞれ\(X, Y\)を超えるようなことが一度もあってはならないのではなく、一度その状態になるとその先は料理を食べられないという構造になっているので、甘さ・しょっぱさが両方ともに限界値以下ならばもう一品食えるという点に注意)

 

D問題での最小の\(d\)を求める部分、およびE問題での\(dp\)のキーと値を交換するという発想は典型的手法らしいので確実に今回で習得したい・・・。


Viewing all articles
Browse latest Browse all 7890

Trending Articles