Processing math: 100%

総和がSになる数列の個数

整数 a+b+c+...=S を満たすような (a,b,c,...) の組の個数の数え上げ方。

S 個のボールを箱に入れる問題とも言う。

順番を区別

S=6 のとき、(2,1,3)(3,2,1) などは別々に数える場合。

ボールと箱の問題に置き換えたときの、箱を区別する場合。

基本的にこちらの方が数えやすい。

項数に制約無し

S を正整数に分割する方法: 2S1

|------------ S -----------|
 ○  ○  ○  ○  ○  ○  ○
   ↑  ↑  ↑  ↑  ↑  ↑


 ○  ○|○  ○  ○|○  ○  =  (2, 3, 2)
 ○|○  ○|○|○|○  ○  =  (1, 2, 1, 1, 2)

それぞれの↑に区切りを入れるか入れないか。

項数は k

Sk 個の正整数に分割する方法: S1Ck1

 |------------ S -----------|
  ○  ○  ○  ○  ○  ○  ○
    ↑  ↑  ↑  ↑  ↑  ↑

S1 箇所のどこかに区切りを k1 個入れるパターンと言い換えられる。

k 個の非負整数に分割する場合は、S+k1Ck1 となる。
S+kk 個の正整数への分割方法を求めた後、k 項を1個ずつ減らすことをイメージする。

順番を区別しない(組合せ数)

S=6 のとき、(2,1,3)(3,2,1) などは1つと数える場合。

ボールと箱の問題に置き換えたときの、箱を区別しない場合。

分割数、英語では partition と呼び、その場合の数は number of partitions となる。

項数に制約無し

S を正整数に分割する。

最大でも項数は S なので、下記の「項数は k」の場合の k=1S を足し合わせたものが答えとなる。

項数は k

Sk 個の正整数に分割する。

正整数でなく k 項の非負整数に分割するなら、足りない項数をゼロ埋めすれば、1k 項の正整数に分割した場合の総和と同じことになる。

S=6
1以上                      0以上(k=4)
k=1: {6}               →  {0,0,0,6}
k=2: {1,5},{2,4} etc.  →  {0,0,1,5},{0,0,2,4}
k=3: {1,1,4} etc.      →  {0,1,1,4}
k=4: {1,1,2,2} etc.    →  {1,1,2,2}

DPで求める

a(0,0)=1、他を 0 で初期化する。以下で求められる。

  • a(S,k)=a(Sk,k)+a(S1,k1)
  • 以下の合計だと考える
    • a(Sk,k): 全ての項が2以上の場合、1ずつ減らした場合の数と一致
    • a(S1,k1): 1の項がある場合、それを除いた場合の数と一致

または、以下でもよい。
右辺は非負整数への分割の方法の数で、その各項に等しく1を加えた結果は a(S,k) と一致する。

  • a(S,k)=a(Sk,1)+a(Sk,2)+...+a(Sk,k)

計算量はいずれも O(Sk)

母関数から求める

k を固定した時の a(1),a(2),... の母関数は、1(1x)(1x2)(1x3)...(1xk) となるらしい。

証明は上記のリンク先のpdfにあるが、難しい。

ともかく、これを計算した時の xS の係数が答えとなる。

これは、競プロ界隈では“きたまさ法”や“高速きたまさ法”と呼ばれている方法で O(k2logS)O(klogklogS) で求められる。

大小関係の構成による場合分け

Sk=6 個への分割で、昇順に並べたときの6項間の関係がたとえば A<B=C<D=E=F になるようなものの個数を求める。

この関係性のパターンは、k1 個ある2項間がそれぞれ <= かで 2k1 パターン存在する。 全て調べて総和を取ると、項数が k になる分割数と一致する。

同じ値が何個、何組あるかの構成が重要な場合に用いるが、 上記の通り全探索には 2k1 かかるのであまり大きな k には使えない。

A から順に値を決めてDPすることで O(Sk) くらいで求めることも可能だが、 ある関係性パターンに対して O(k6logS)O(k2logklogS) などで求める方法もある。

先頭に便宜的に0を補い差分を取ると、S は以下のように表せる。

0 < A < B = C < D = E = F
                *   *   *    CD間の差分 z * 3  -,
        *   *   *   *   *    AB間の差分 y * 5  -| 合計がS
    *   *   *   *   *   *    0A間の差分 x * 6  -'

6x+5y+3z=S を満たす正整数 (x,y,z) の組の個数に言い換えられ、 これは順序も区別するので、より数えやすい形となる。

和が S となる組の個数を aS として包除原理を使うと、以下のように表せる。

  • aS=aS6+aS5+aS3aS65aS63aS53+aS653
    • 1項が1小さいケース - 2項が1小さいケース + 3項が1小さいケース
    • 変数が4以上の場合も、同様に足し引きする

これは、aS の14項間漸化式となる。

漸化式は行列の形で表せ、これはダブリングにより logS で行える。

(aSaS1aS2aS3aS13)=(0010110110100110000000000000010000000000000010000000000000000000000010)(aS1aS2aS3aS4aS14)=(00111000010000100000)S14(S14S13S12S11S1)

行列サイズが最大で O(k2)、このダブリング計算は O(k6logS) かかる。

全ての関係パターンについて計算する場合は、計算量の立式がよくわからないけど、logS を除いた部分の計算量が k=102×107 を超えてくる。

ここでも高速きたまさ法や、線形漸化式を満たす数列の N 項目を計算するアルゴリズム を使うと、 k を固定したときの計算量が O(k2logklogS) に落とせ、全パターンでも k=12107 を超える程度となる。(あんまかわんないな)

k が小さいときに限るが、このようにすれば任意の大小関係での分割数を求められる。

programming_algorithm/number_theory/partitions.txt · 最終更新: 2021/04/14 by ikatakos
CC Attribution 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0