差分

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

この比較画面へのリンク

両方とも前のリビジョン前のリビジョン
次のリビジョン
前のリビジョン
次のリビジョン両方とも次のリビジョン
programming_algorithm:contest_history:atcoder:2019:0106_educational_dp [2019/01/10] – [解法] ikatakosprogramming_algorithm:contest_history:atcoder:2019:0106_educational_dp [2019/01/10] – [解法] ikatakos
行 1: 行 1:
-======Educational DP Contest I,K,Lメモ======+======Educational DP Contest I,K,L,Mメモ======
  
 [[https://atcoder.jp/contests/dp|Educational DP Contest / DP まとめコンテスト - AtCoder]] [[https://atcoder.jp/contests/dp|Educational DP Contest / DP まとめコンテスト - AtCoder]]
行 169: 行 169:
 </sxh> </sxh>
  
 +===== M - Candies =====
  
 +[[https://atcoder.jp/contests/dp/tasks/dp_m|M - Candies]]
 +
 +==== 問題 ====
 +
 +  * $K$ 個のキャンディを、余りなく $N$ 人の子供に分ける
 +  * 各子供には上限 $a_1,a_2,...,a_N$ が決められており、$i$ 人目の子供には 0以上$a_i$以下の個数のキャンディをあげることができる
 +  * 配り方のパターン数を、$\mod{10^9+7}$ で求めよ
 +  * $1 \le N \le 100$
 +  * $1 \le K \le 10^5$
 +
 +==== 解法 ====
 +
 +愚直にやる方法は基本的なDPで実装できるけど、遷移が多くてTLEになるので、上手く圧縮する。
 +
 +===愚直な方法===
 +
 +==データ==
 +$DP[i][j]=i$人目までの子供に、$j$ 個の飴を配るパターン数
 +
 +として考える。$j$ の範囲は $0~K$ で用意することになる。
 +
 +==初期状態==
 +$DP[0][0]=1$、後は0
 +
 +==遷移==
 +$i-1$ までのDPが以下のような感じで、$a_i=2$ だった場合の遷移を考える。
 +
 +  ↑j |   ...                 ...
 +    5 |   25     25 +20 +15 = 60
 +    4 |   20     20 +15 + 9 = 44
 +    3 |   15     15 + 9 + 8 = 32
 +    2 |    9      9 + 8 + 1 = 18
 +    1 |    8      8 + 1      9
 +    0 |    1      1          1
 +  ----+-------------------------
 +      |   i-1                  i
 +                         ↑2個配った時の遷移
 +                     ↑1個配ったときの遷移
 +                 ↑0個配ったときの遷移
 +
 +この、○個配ったときの各遷移の各 $j$ につき、$DP[i-1]$ の参照と $DP[i]$ への加算が発生するので、$i-1$ から $i$ への遷移で計算が $K \times a_i$ 回発生することになる。それぞれ上限 $10^5$ なので、間に合わない。
 +
 +===圧縮===
 +
 +==遷移==
 +
 +全体を把握するため、もう少し少ない例でやってみる。
 +
 +  ↑j |                               1=1
 +    5 |                             1+2=3
 +    4 |                           1+2+2=5
 +    3 |                   1=1   1+2+2+1=6
 +    2 |                 1+1=2   2+2+1  =5
 +    1 |         1=1   1+1  =2   2+1    =3
 +    0 |      =1      =1        =1
 +  ----+-----+-------+---------+-----------
 +      |      a1=1      a2=2        a3=3
 +
 +
 +なんか規則性がありそう。
 +
 +「$a_i$ による上限を設けない」場合との差を考えてみる。
 +
 +  ↑j |            ...
 +    7 |              1+2+2+1=6       1+2+2+1=6
 +    6 |            1+2+2+1  =6       2+2+1  =5
 +    5 |          1+2+2+1    =6       2+1    =3
 +    4 |        1+2+2+1      =6            =1
 +    3 |  1   1+2+2+1        =6
 +    2 |  2   2+2+1          =5
 +    1 |  2   2+1            =3
 +    0 |  1                =1
 +  ----+----+-------------------+--------------------
 +      | i=2               i=3    i=3における上限あるなしの差分
 +
 +上限を設けない場合、配り方のパターン数は、直前の状態(1,2,2,1)の累積和となる。また、差分は、累積和をそのまま $a_i+1$ だけずらしたものとなる。
 +
 +よって、累積和でまとめてしまえば、1回の遷移にかかる計算を上限 $K$ 回に省略でき、間に合う。
 +
 +<sxh python>
 +from itertools import accumulate, starmap
 +from operator import sub
 +
 +n, k = map(int, input().split())
 +aaa = list(map(int, input().split()))
 +MOD = 10 ** 9 + 7
 +dp = [0] * (k + 1)
 +dp[0] = 1
 +for a in aaa:
 +    dp = list(accumulate(dp))
 +    dp[a + 1:] = starmap(sub, zip(dp[a + 1:], dp[:-a - 1]))
 +    dp = [x % MOD for x in dp]
 +print(dp[k])
 +</sxh>
programming_algorithm/contest_history/atcoder/2019/0106_educational_dp.txt · 最終更新: 2019/01/21 by ikatakos
CC Attribution 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0