Introduction
Finding the combinations can be done using a simple counting algorithm. Use an array of "digits" where each digit has the value 1 through N. The number of digits in the array is K. Updating the array to find the next valid solution takes amortized O(1) time, since in most cases only a few digits at the end of the array change.
The process of updating the array is similar to normal counting:
- increment the rightmost digit (the least significant digit)
- if it exceeds its maximum, set it back to its minimum, and carry into the next digit
- repeat until no carry is necessary
- if there's a carry out of the most significant digit, then terminate the search
Generating the combinations of K values is a little more complicated because the minimum and maximum digit values are not fixed numbers. But the concept is the same.
The minimum value for a digit has the following constraints:
- the digit shall not be less than 1
- the digit shall not be less than the digit to its left (this prevents duplicate combinations)
- the digit shall be large enough that the sum of the array can be greater than or equal to Z
The maximum value for a digit has the following constraints:
- the digit shall not be greater than N
- the digit shall be small enough that the sum of the array can be less than or equal to Z
Example
The following example assumes the input parameters are K=16, N=32, Z=64. The algorithm uses two arrays to generate solutions:
- The first is the
digitArray
, which contains K elements, each of which has a value between 1 and N. After each update of the digitArray
, the sum of the elements is always Z.
- The second array is the
prefixSumArray
. The prefixSumArray
is only needed as an optimization. Without it, computing the sum of the "blue" digits would take O(K) time.
The digitArray
is conceptually divided into three subarrays as shown below. In the description that follows, the green element is the element being processed. Blue elements are either untouched (while scanning right-to-left), or have been finalized (while scanning left-to-right). Red elements are waiting to be assigned a new value.

Two consecutive solutions to the problem are shown below. It is the transformation from one to the other that this example strives to illustrate.
[1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 3, 11, 11, 12, 12]
[1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 4, 4, 5, 32]
The initial state of the digit array, with the corresponding prefix sum array:

The code starts by incrementing the right-most digit. That digit will always overflow, and generate a carry, because it only has one possible value (which is the value that makes the array sum equal to Z). Setting the digit to its minimum value is deferred.

The code then increments the second digit (from the right). That results in an array with a partial sum of 53, and one unknown digit at the end. That last digit must be at least 13 (it can't be less than the digit to its left). A value of 13 in the last digit brings the sum to 66, which is greater than Z. So the second digit has overflowed, and will be set to its minimum.

After incrementing the third digit, the partial sum is 41. The two red digits must be at least 12 each, bringing the sum to 65. The third digit has overflowed.

The fourth digit also overflows, but this time let's demonstrate that by computing the maximum value for the digit. The maximum is
(Z - sum_of_blue) / (count_of_red + 1) = (64 - 18) / (3 + 1) = 11
So it overflows after 11.

The fifth digit has a maximum of (64 - 15) / (4 + 1) = 9
. So incrementing it from 3 to 4 does not cause an overflow.

Now the code needs to set all of the red digits to their minimum values (updating the prefix sum array at the same time). The minimum for a digit is found by assuming that all the digits to the right are equal to N. So the minimum is
(Z - sum_of_blue) - (N * count_of_red) = (64 - 19) - (32 * 3) = -51
That's less than the digit to the left, so the minimum is 4.

The next digit has a minimum value of (64 - 23) - (32 * 2) = -23
, so that digit is set to 4.

The next digit has a minimum value of (64 - 27) - (32 * 1) = 5

And the final digit has a minimum value of (64 - 32) - (32 * 0) = 32

And the final result is the next solution in the sequence.

Code
Here's a sample implementation in C:
#include <stdio.h>
#include <stdbool.h>
void showArray(int count, int digitArray[], int K)
{
printf("%5d: [%2d", count, digitArray[0]);
for (int i = 1; i < K; i++)
printf(", %2d", digitArray[i]);
printf("]\n");
}
// The 'computeMinimums' function sets the red elements in the 'digitArray'
// to their minimum allowed value, while updating the 'prefixSumArray'.
// The 'start' parameter is the index of the first red element.
void computeMinimums(int digitArray[], int prefixSumArray[], int start, int K, int N, int Z)
{
int leftDigit = 1; // value of the element to the left of the current digit
int leftSum = 0; // sum of the elements to the left of the current digit
if (start > 0)
{
leftDigit = digitArray[start-1];
leftSum = prefixSumArray[start-1];
}
int rightSum = (K - start - 1) * N; // maximum sum for the red digits
for (int i = start; i < K; i++)
{
// compute the minimum value for the current digit
int minDigit = Z - leftSum - rightSum;
if (minDigit < leftDigit)
minDigit = leftDigit;
// prepare for the next digit
leftDigit = minDigit;
leftSum += minDigit;
rightSum -= N;
// update the current element in the arrays
digitArray[i] = minDigit;
prefixSumArray[i] = leftSum;
}
}
bool nextSolution(int digitArray[], int prefixSumArray[], int K, int N, int Z)
{
// starting with the rightmost digit, scan backwards through the array
// to find a digit that can be incremented without overflowing
for (int i = K-1; i >= 0; i--)
{
// compute the maximum value for the current digit
int leftSum = prefixSumArray[i] - digitArray[i];
int maxDigit = (Z - leftSum) / (K - i);
if (maxDigit > N)
maxDigit = N;
// Increment the current digit, and if it doesn't overflow,
// then there is a solution.
// Update the prefix sum array, and fill in the red array elements.
digitArray[i]++;
if (digitArray[i] <= maxDigit)
{
prefixSumArray[i]++;
computeMinimums(digitArray, prefixSumArray, i+1, K, N, Z);
return true;
}
}
// all of the digits overflowed, so there are no more solutions
return false;
}
int main(void)
{
int K = 16;
int N = 32;
int Z = 64;
int digitArray[K];
int prefixSumArray[K];
// fill the digitArray with the first solution, and initialize the prefix sums
computeMinimums(digitArray, prefixSumArray, 0, K, N, Z);
for (int count = 1; ; count++)
{
// output the current solution
showArray(count, digitArray, K);
// generate the next solution, end the loop if there are no more
if (!nextSolution(digitArray, prefixSumArray, K, N, Z))
break;
}
}