差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

両方とも前のリビジョン前のリビジョン
次のリビジョン
前のリビジョン
次のリビジョン両方とも次のリビジョン
programming_algorithm:contest_history:atcoder:2019:0106_educational_dp_4 [2019/02/08] – [解法] ikatakosprogramming_algorithm:contest_history:atcoder:2019:0106_educational_dp_4 [2019/02/08] – [解法] ikatakos
行 241: 行 241:
  
 優先順位付きナップサック問題。 優先順位付きナップサック問題。
 +
 +自分より上のブロックの重さは丈夫さに関わるため、実際のタワーのように下から積み上げるのではなく、上から決めていく。
  
 === データ === === データ ===
行 246: 行 248:
  
 === 初期条件 === === 初期条件 ===
--1など、重さ $j$ が処理済/未処理であることが区別できる値で全て埋めておく+$DP[0][0]=0$ 
 + 
 +他は、重さ $j$ が実現可能/不可能であることが区別できるよう、-1など正しい重さになり得ない値で埋めておく 
  
 === 優先順位 === === 優先順位 ===
  
 遷移の前に、優先順位を求める。 遷移の前に、優先順位を求める。
-重たいブロックを上に積むのは非効率なので、に積んだ方がよいブロックの順序があると予測する。+重たいブロックを上に積むのは非効率なので、優先的に積んだ方がよいブロックの順序があると予測する。
  
 ある2つのブロック $i,j$ があり、2つとも使うことを考える。2つの上に積み上がったブロックの重さの総和を $X$ とする。 ある2つのブロック $i,j$ があり、2つとも使うことを考える。2つの上に積み上がったブロックの重さの総和を $X$ とする。
  
-$i$ の方を上にしないと、$j$ が上だと積めなくなる場合というの+$i$ を上にする両方積めるが、$j$ が上だと積めなくなる場合があったすると、次が同時に成立してずである。
  
   * $X+w_i \le s_j$   * $X+w_i \le s_j$
   * $X+w_j \gt s_i$   * $X+w_j \gt s_i$
  
-となるXが存在するはずである。(問題指定のブロックで実現できるかは別として、数値として) +これを移項してXを消去すると、$s_i+w_i \lt s_j+w_j$ となる。重さと丈夫さの和が小さいブロックから上にした方がよいことが分かる。
- +
-これを移項してXを消去すると、$s_i+w_i \lt s_j+w_j$ となり、重さと丈夫さの和が小さいブロックから上にした方がよいことが分かる。+
  
 === 遷移 === === 遷移 ===
行 268: 行 271:
 あとは普通のナップサックDP。 あとは普通のナップサックDP。
  
-丈夫さの上限が $10^4$ なので、考慮すべき重さの総計は多くとも $2 \times 10^4$ まででよい。+重さと丈夫さの上限が $10^4$ なので、考慮すべき重さの総計は多くとも $2 \times 10^4$ まででよい。
 ($w_i=10^4,s_i=10^4$ のブロックに、重さの合計が $10^4$ のタワーを乗せた場合が、タワー全体の重さの取り得る最大値) ($w_i=10^4,s_i=10^4$ のブロックに、重さの合計が $10^4$ のタワーを乗せた場合が、タワー全体の重さの取り得る最大値)
  
行 312: 行 315:
  
 こういう、序盤の敵がアレンジされて強くなって終盤に出てくるのって、RPG的でいいよね。 こういう、序盤の敵がアレンジされて強くなって終盤に出てくるのって、RPG的でいいよね。
 +
 +===方針===
  
 $N$ の制約がそこまで多くないので、包除原理DPを行う。 $N$ の制約がそこまで多くないので、包除原理DPを行う。
- 
-「1回も壁を通過しないパターン数」=「全体のパターン数」-「1回でも壁を通過しちゃうパターン数」 
- 
-===方針=== 
  
 壁マスでも通過できるとして、"少なくとも $k$ 個の壁マスを通過した" 経路のパターン数を $f(k)$ とすると、包除原理より 壁マスでも通過できるとして、"少なくとも $k$ 個の壁マスを通過した" 経路のパターン数を $f(k)$ とすると、包除原理より
行 342: 行 343:
 この「他の●を通ったかどうかは関係ない」というところが、経路数の計算を単純明快にしてくれる。 この「他の●を通ったかどうかは関係ない」というところが、経路数の計算を単純明快にしてくれる。
  
-下に $x$ マス、右に $y$ マス移動する経路数は、合計 $x+y$ 回の移動から下移動に当てはまる $x$ 回の移動の選び方になるので、${}_{x+y}C_{x}$ 通り。+下に $x$ マス、右に $y$ マス移動する経路数は、合計 $x+y$ 回の移動から下移動に当てはまる $x$ 回の移動の選び方になるので、${}_{x+y}C_{x}$ 通りと計算できる
  
 それを踏まえて、必要なDPを考える。 それを踏まえて、必要なDPを考える。
  
 === データ === === データ ===
-$DP[i][j]=$ Sマスから $i$ 個目の壁マスまでの、今まで少なくとも通過した壁マスが自身を含め $j=[0:偶数,1:奇数]$ 個の場合の経路数+$DP[i][j]=$ Sマスから $i$ 個目の壁マスまでの、通過した壁マスが少なくとも自身を含め $j=[0:偶数,1:奇数]$ 個の場合の経路数
  
 さらに、最終的に必要なのは通過した壁マスが(偶数個)-(奇数個)の情報だけで、かつ偶数個でも奇数個でも遷移はかけ算のみで行える(=[[wpjp>分配法則]]が成り立つ)ので、以下のようにするとより省計算量・省メモリになる。 さらに、最終的に必要なのは通過した壁マスが(偶数個)-(奇数個)の情報だけで、かつ偶数個でも奇数個でも遷移はかけ算のみで行える(=[[wpjp>分配法則]]が成り立つ)ので、以下のようにするとより省計算量・省メモリになる。
  
-$DP[i]=$ Sマスから $i$ 個目の壁マスまでの、今まで少なくとも通過した壁マスが(偶数個の場合の経路数)-(奇数個の場合の経路数)+$DP[i]=$ Sマスから $i$ 個目の壁マスまでの、通過した壁マスが少なくとも自身を含め(偶数個の場合の経路数)-(奇数個の場合の経路数)
  
 === 初期条件 === === 初期条件 ===
行 360: 行 361:
 つまり、右か下に移動する特性上、ソート順で後→前の順番で通過することはできない。 つまり、右か下に移動する特性上、ソート順で後→前の順番で通過することはできない。
  
-これにより、$i$ 番目の壁マスを考えるとき、$DP[1]~DP[i-1]$ にいては確定していることを保証できる。+これにより、$i$ 番目の壁マスを考えるとき、$DP[1]~DP[i-1]$ にいては確定していることを保証できる。
  
 $i$ 番目の壁マスを考える。Sマスと $1~i-1$ 番目の壁マスの、それぞれからの$i$ 番目の壁への経路数を求める。 $i$ 番目の壁マスを考える。Sマスと $1~i-1$ 番目の壁マスの、それぞれからの$i$ 番目の壁への経路数を求める。
行 367: 行 368:
  
   * $c_j \gt c_i$ の時、$p_{j,i}=0$   * $c_j \gt c_i$ の時、$p_{j,i}=0$
-  * $c_j \le c_i$ の時、$p_{j,i}=$さっきの${}_{x+y}C_{x}$の計算で求められる経路数+  * $c_j \le c_i$ の時、$p_{j,i}={}_{dx+dy}C_{dx}$で求められる経路数
  
 計算の便宜上、Sマスも"0番目の壁マス"と見做すとして、以下で遷移できる。 計算の便宜上、Sマスも"0番目の壁マス"と見做すとして、以下で遷移できる。
行 373: 行 374:
 $\displaystyle DP[i] = \sum_{k=0}^{i-1}(-DP[k] \times p_{k,i})$ $\displaystyle DP[i] = \sum_{k=0}^{i-1}(-DP[k] \times p_{k,i})$
  
-DP[k] では(偶数個)-(奇数個)の値だったものが、$i$ 番目の壁マスを踏むことによって一律1個ずつ増えて(奇数個)-(偶数個)になるので、更新時に正負逆転させておくのが重要。+DP[k] では(偶数個)-(奇数個)の値だったものが、遷移すると $i$ 番目の壁マスを踏むことによって一律1個ずつ増えて(奇数個)-(偶数個)を示す値になるので、更新時に正負逆転させておくのが重要。
  
 計算の便宜上、Gマスも"N+1番目の壁マス"と見做して同様に計算すると、答えは $-DP[N+1]$ となる。 計算の便宜上、Gマスも"N+1番目の壁マス"と見做して同様に計算すると、答えは $-DP[N+1]$ となる。
 (本来は壁マスでないGマスを壁マスとして計算しているため、DP上では正負逆転した値となっている) (本来は壁マスでないGマスを壁マスとして計算しているため、DP上では正負逆転した値となっている)
  
 +
 +%%c++%% の場合は負数%正数が負になるので注意。Pythonでは正となるので、そのまま出力できる。
  
 <sxh python> <sxh python>
programming_algorithm/contest_history/atcoder/2019/0106_educational_dp_4.txt · 最終更新: 2019/02/26 by ikatakos
CC Attribution 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0