Counting DP

Counting DP is a method that uses a memorized search similar to DP (which differs somewhat from DP in the narrow sense, namely optimization problems) to solve counting (and summation) problems.

Basics

Basic idea

A counting problem generally asks for the size of a set SS. In OI, the size of SS may sometimes reach the order of Θ(nn)\Theta(n^n) or even Θ(2n!)\Theta(2^{n!}) (of course, it is generally taken modulo some fixed number), where nn is the problem size, so we cannot find the elements of SS one by one.

If we can divide SS into several pairwise disjoint subsets, then the number of elements in SS equals the sum of the numbers of elements in these parts. If counting these subsets happens to resemble the original problem, we can solve it using a method similar to dynamic programming.

Example

Example

Given a positive integer nn, find the number of ways to express nn as the sum of kk positive integers, where changing the positions counts as a different partition.

Let Sn,kS_{n,k} be the set of tuples of positive integers of the form (a1,…,ak)(a_1, \dots, a_k) such that a1+⋯+ak=na_1 + \dots + a_k = n. If aka_k is fixed, we have the following derivation: since a1+a2+⋯+ak−1+ak=na_1 + a_2 + \dots + a_{k-1} + a_k = n, we have a1+a2+⋯+ak−1=n−aka_1 + a_2 + \dots + a_{k-1} = n - a_k. By the definition of Sn,kS_{n,k}, (a1,a2,…,ak−1)∈Sn−ak,k−1(a_1, a_2, \dots, a_{k-1}) \in S_{n - a_k, k - 1}.

Since a1,a2,…,aka_1, a_2, \dots, a_k are positive integers, the range of aka_k is [1,n−k+1]∩Z[1, n - k + 1] \cap \mathbb Z. Therefore, Sn,kS_{n,k} can be partitioned according to aka_k into n−k+1n - k + 1 subsets. When ak=ia_k = i, the subset is:

{(L,i)∣L∈Sn−i,k−1}.\{(L, i) \mid L \in S_{n-i,k-1}\}.

The number of elements in this subset is clearly equal to that of Sn−i,k−1S_{n-i,k-1}, and because the values of ii differ, these subsets are pairwise disjoint. Therefore:

∣Sn,k∣=∑i=1n−k+1∣Sn−i,k−1∣.|S_{n,k}| = \sum_{i=1}^{n-k+1} |S_{n-i,k-1}|.

We can therefore process this using a method similar to DP: let fn,kf_{n,k} be ∣Sn,k∣|S_{n,k}|. Then the state transition is:

fn,k=∑i=1n−k+1fn−i,k−1.f_{n,k} = \sum_{i=1}^{n-k+1} f_{n-i,k-1}.

Thus, it can be solved using DP.

Similarities to and differences from optimization DP

We can see that both counting DP and optimization DP find a value (a size or an optimum) over a domain Ω\Omega. This value is obtained by processing every element in Ω\Omega once and then aggregating the processed values once.

For example, in the 0-1 knapsack problem, the elements of Ω\Omega are the sets of all items in the knapsack. For a solution in Ω\Omega, SS, we process SS once; the result w(S)w(S) is the total value of the items in SS. We take the maximum over all processed values to obtain the answer.

For a counting problem, the elements of Ω\Omega are the set SS whose number of elements is to be computed. Its processing changes every element of SS to 11, and then aggregates these 11s by addition. Since every element of SS corresponds to one 11, the resulting value is the number of elements in SS.

When the aggregation operation is taking a maximum or minimum, we may divide Ω\Omega into any number of parts, as long as their union is Ω\Omega; pairwise disjointness is not required. Counting problems do not satisfy this condition, so we need to divide Ω\Omega into parts that are pairwise disjoint. This is the difference from optimization DP.

Example

Example

Given a positive integer nn, find the number of ways to express nn as the sum of any number of positive integers, where changing the positions counts as the same partition.

Solution 1

The elements of the set to be computed are positive-integer multisets whose sum is nn. However, this is clearly not easy to derive from directly.

If a multiset TT contains only positive integers ≤M\le M and the sum of all elements in TT is nn, define T∈Sn,MT \in S_{n, M}. Consider the number of occurrences of MM. It may be k∈[0,⌊nM⌋]∩Zk \in \left[0, \left\lfloor \dfrac nM \right\rfloor\right] \cap \mathbb Z. Thus, it can transition to Sn−kM,M−1S_{n - kM, M - 1}. Summing over these gives a complexity of Θ(n2log⁡n)\Theta(n^2 \log n) (the log⁡\log comes from the harmonic series caused by the range of kk).

However, this is still not good enough. Consider the following example:

f8,3=f8,2+f5,2+f2,2f9,3=f9,2+f6,2+f3,2+f0,2f10,3=f10,2+f7,2+f4,2+f1,2f11,3=f11,2+f8,2+f5,2+f2,2f12,3=f12,2+f9,2+f6,2+f3,2+f0,2f13,3=f13,2+f10,2+f7,2+f4,2+f1,2\begin{aligned} f_{8, 3} &= {\color{red}f_{8, 2} + f_{5, 2} + f_{2, 2}} \\ f_{9, 3} &= {\color{blue}f_{9, 2} + f_{6, 2} + f_{3, 2} + f_{0, 2}} \\ f_{10, 3} &= {\color{green}f_{10, 2} + f_{7, 2} + f_{4, 2} + f_{1, 2}}\\ f_{11, 3} &= f_{11, 2} + {\color{red}f_{8, 2} + f_{5, 2} + f_{2, 2}}\\ f_{12, 3} &= f_{12, 2} + {\color{blue}f_{9, 2} + f_{6, 2} + f_{3, 2} + f_{0, 2}}\\ f_{13, 3} &= f_{13, 2} + {\color{green}f_{10, 2} + f_{7, 2} + f_{4, 2} + f_{1, 2}}\\ \end{aligned}

Substitution gives f11,3=f11,2+f8,3f_{11, 3} = f_{11, 2} + f_{8, 3}, f12,3=f12,2+f9,3f_{12, 3} = f_{12, 2} + f_{9, 3}, and f13,3=f13,2+f10,3f_{13, 3} = f_{13, 2} + f_{10, 3}. Similarly, we can obtain a general state transition:

fn,M=fn,M−1+{fn−M,Mn≥M,0otherwise.f_{n, M} = f_{n, M - 1} + \begin{cases} f_{n - M, M} & n \ge M, \\ 0 & \text{otherwise}. \end{cases}

The time complexity is now Θ(n2)\Theta(n^2).

Solution 2

Considering that a multiset of positive integers TT can necessarily be obtained by the two operations “increment every element in TT” and “add to TT an element with value 11”, different operation sequences produce different results.

Thus, the transition for TT can be changed into a transition for operation sequences. Consider the last operation in an operation sequence that partitions nn into mm numbers (denote all such operation sequences by Bn,mB_{n,m}). If it is operation 11, the number of elements does not increase, but ∑T\sum T increases by mm. For the final ∑T=n\sum T = n, the sum of the original TT (denoted by T′T') must be n−mn-m. Hence Bn,m→Bn−m,mB_{n,m} \to B_{n-m,m}. If it is operation 22, the number of elements increases by one and ∑T\sum T increases by 11. Hence Bn,m→Bn−1,m−1B_{n,m} \to B_{n-1,m-1}.

The time complexity remains Θ(n2)\Theta(n^2).

Solution 3

Consider dividing TT into the part greater than n\sqrt n, T1T_1, and the part less than or equal to n\sqrt n, T2T_2. T2T_2 can be found using Solution 1, while the number of T1T_1 can be found by slightly modifying Solution 2: change the two operations to “increment every element in T1T_1” and “add to T1T_1 an element with value ⌊n⌋+1\lfloor \sqrt n \rfloor + 1”. The state transition can be written down easily.

Split nn into two parts, AA and BB. Enumerating one determines the other. Find the number satisfying ∑T1=A\sum T_1 = A among T1T_1 and the number satisfying ∑T2=B\sum T_2 = B among T2T_2, multiply them, and sum over all AA to obtain the final result.

When computing the number of T1T_1, we have M≤nM \le \sqrt n, so using Solution 1 to compute T1T_1 takes Θ(n3/2)\Theta(n^{3/2}) time. Similarly, when computing the number of T2T_2, ∣T2∣≤∑T2n≤nn=n|T_2| \le \dfrac{\sum T_2}{\sqrt n} \le \dfrac{n}{\sqrt n} = \sqrt n, so using Solution 2 to compute T2T_2 also takes Θ(n3/2)\Theta(n^{3/2}) time. Therefore, the total time complexity is Θ(n3/2)\Theta(n^{3/2}).

This content comes from OI Wiki: Counting DP. See the original for authors and revision history. AIOJ has adapted the formatting, in-site links, and resource paths.

Content is shared under CC BY-SA 4.0 and SATA license; additional terms are governed by the original notice. Thanks to the OI Wiki authors and contributors; per the SATA terms, please visit the OI Wiki repository and star it to show your support.