差分

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

この比較画面へのリンク

両方とも前のリビジョン前のリビジョン
次のリビジョン
前のリビジョン
次のリビジョン両方とも次のリビジョン
programming_algorithm:contest_history:atcoder:2019:0106_educational_dp [2019/01/10] – [解法] ikatakosprogramming_algorithm:contest_history:atcoder:2019:0106_educational_dp [2019/01/11] – [解法] ikatakos
行 188: 行 188:
  
 ==データ== ==データ==
-DP[i][j]=iDP[i][j]=i人目までの子供に、jj 個の飴を配るパターン数+DP[i][j]=iDP[i][j]=i人目までの子供に、合計 jj 個の飴を配るパターン数
  
 として考える。jj の範囲は 0K で用意することになる。 として考える。j の範囲は 0K で用意することになる。
行 212: 行 212:
  
 この、○個配ったときの各遷移の各 j につき、DP[i1] の参照と DP[i] への加算が発生するので、i1 から i への遷移で計算が K×ai 回発生することになる。それぞれ上限 105 なので、間に合わない。 この、○個配ったときの各遷移の各 j につき、DP[i1] の参照と DP[i] への加算が発生するので、i1 から i への遷移で計算が K×ai 回発生することになる。それぞれ上限 105 なので、間に合わない。
 +
 +  擬似コード
 +  for i in 1..N:
 +      for k in 0..a:
 +          for j in 0..K:
 +              dp[i][j+k] += dp[i-1][j]
  
 ===圧縮=== ===圧縮===
行 229: 行 235:
       |      a1=1      a2=2        a3=3       |      a1=1      a2=2        a3=3
  
 +/*
 なんか規則性がありそう。 なんか規則性がありそう。
  
行 249: 行 255:
  
 よって、累積和でまとめてしまえば、1回の遷移にかかる計算を上限 K 回に省略でき、間に合う。 よって、累積和でまとめてしまえば、1回の遷移にかかる計算を上限 K 回に省略でき、間に合う。
 +*/
 +
 +a3 に着目すると、
 +
 +  * j=03DP[2][0]=1 を加算
 +  * j=14DP[2][1]=2 を加算
 +  * j=25DP[2][2]=2 を加算
 +  * j=36DP[2][3]=1 を加算
 +
 +という区間加算で表される。よって、いもす法による累積和で高速化できる。
 +
 +  * DP[3][0]に1、DP[3][4]に-1を加算
 +  * DP[3][1]に2、DP[3][5]に-2を加算
 +  * DP[3][2]に2、DP[3][6]に-2を加算
 +  * DP[3][3]に1、DP[3][7]に-1を加算
 +  * DP[3]の累積和を取る
 +
 +ここで、正の加算の部分はそのままDP[2]で流用でき、負の部分はDP[2]ai+1だけずらして正負逆転させたものに一致する。
 +
 +よって、計算量を上限K回の減算+累積和の計算に省略でき、間に合う。
  
 <sxh python> <sxh python>
行 265: 行 291:
 print(dp[k]) print(dp[k])
 </sxh> </sxh>
 +
 +このような行列同士の四則演算はNumPyを使いたくなるけど、一括で累積和を計算したらオーバーフローを起こすのか、WAになってしまった。
 +
 +う~ん、Kの上限が106で、各項が剰余を取って109+7未満なので、最大でも1015強にしかならないはずなんだけどなあ。WAの原因は他にあるのだろうか。
 +
 +
 +
programming_algorithm/contest_history/atcoder/2019/0106_educational_dp.txt · 最終更新: by ikatakos
CC Attribution 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0