It is easier to approach the more general problem of determining how many ways the first son can get the value of k , where k is a parameter. There is art to clarify the corresponding generalization; he taught in courses in algorithms called dynamic programming.
Let x be a variable. Mathematical insight is needed, since for paintings n coefficient at x^k in the product of polynomials
x (1 + x^2) (1 + x^3) ... (1 + x^n)
in x is the number of ways in which the first son can get the value of k (including coloring the value 1 ). This is due to the fact that this product applies to
(sum for i_2 = 0 to 1) (sum for i_3 = 0 to 1) ... (sum for i_n = 0 to 1) x^(1 + 2 i_2 + 3 i_3 + ... + n i_n),
which is effective, as your brute force solution evaluates this product. A dynamic program here is equivalent to a distribution of coefficients one after another, and not immediately, for example,
x (1 + x^2) = x + x^3 x (1 + x^2) (1 + x^3) = (x + x^3) (1 + x^3) = x + x^3 + x^4 + x^6. x (1 + x^2) (1 + x^3) (1 + x^4) = (x + x^3 + x^4 + x^6) (1 + x^3) = x + x^3 + x^4 + x^6 + x^4 + x^6 + x^7 + x^9 = x + x^3 + 2 x^4 + 2 x^6 + x^7 + x^9.
Time savings come from repetitive terms. We already have only six terms, instead of eight (two to three).
Saving only the last ten digits means that we can evaluate this product in the ring of integers modulo 10^10 . As a result, we can reduce the intermediate coefficients modulo this number so as not to resort to bonuses. This trick, well known to the competitive community of programmers, is officially distributed in courses on abstract algebra or number theory.
In Mathematica :
In[1]:= Coefficient[x Product[1+x^i,{i,2,7}],x^(Sum[i,{i,1,7}]/2)] Out[1]= 4 In[2]:= Coefficient[x Product[1+x^i,{i,2,8}],x^(Sum[i,{i,1,8}]/2)] Out[2]= 7
In Java:
public class PartitionPaintings { public static void main(String[] args) { long[] p = new long[] {0, 1}; for (int i = 2; i <= Integer.parseInt(args[0]); i++) { long[] q = new long[p.length + i]; for (int k = 0; k <= p.length - 1; k++) { for (int j = 0; j <= 1; j++) { q[k + i * j] = (q[k + i * j] + p[k]) % 10000000000L; } } p = q; } System.out.println(p[(p.length - 1) / 2]); } }