分割数のいい感じの問題!
問題概要
長さ の数列
killA
, killB
が与えられる。この 2 つの広義単調減少である。
次の条件を満たす長さ の数列
deathA
, deathB
の組の個数を 1000000007 で割ったあまりを求めよ。
killA
の総和 =deathB
の総和killB
の総和 =deathA
の総和killA[i]
=killA[j]
かつならば、
deathA[i]
deathA[i]
であるkillB[i]
=killB[j]
かつならば、
deathB[i]
deathB[i]
である
制約
killA
,killB
の要素の総和は以下
考えたこと
分割数が活躍する問題だ。
分割数は、「自然数 を
個の 0 以上の整数の和で表す方法の数」のことであり、
と表すことにする。。ただし、和として表すときの順序は問わない。
たとえば、 のときは
というように 5 通りの方法があるので、 である。
分割数は、次の漸化式で求められる。
この漸化式の導出方法としては、自然数 を
個の 0 以上の整数の和で表す方法のうち、
を含むものと含まないものに場合分けして考える。
を含むとき、その
を除去しても方法の数は変化しないので、
を
個の整数の和として表す方法の個数に等しい。よって、
通り。
を含まないとき、和が
となる
個の各整数から
ずつ引くことで、「
を
個の
以上の整数の和として表す方法」に帰着される。よって、
通り。
これらをまとめて、上記の漸化式が得られる。
今回の問題
今回の問題では、killA
, killB
の値が等しい区間の扱いが若干面倒である。killA
, killB
が等しい区間はまとめて処理したい。
そこで、数列 を次のように、整数値のペアの列とする。
= (
killA
において 番目に大きい数
,
killA
におけるその数の個数 )
このとき、deathA
の個数を求めるのは次の DP でできる。なお、deathB
の方も同様である。
dp[i][j]
← deathA
の先頭から 個までについて、総和が
となるようなものの個数
DP の遷移は次のように書ける。分割数が登場する。
dp[i+1][j+k]
+=
dp[i][j]
計算量は = (
killA
や killB
の総和としてあり得る最大値) として、
- 分割数を前処理する:
- DP する:
となる。