Suppose you are given a list L of n numbers and an integer k
Yes, there is a way. Consider the polynomial
(X + a[0]) * (X + a[1]) * ... * (X + a[n-1])
Its coefficients are just the sums of the k-products, its degree is n, so you can calculate the sum of all k-products for all k simultaneously in O(n^2) steps.
After s steps, the coefficient of Xs-k is the sum of the k-products of the first s array elements. The k-products of the first s+1 elements fall into two classes, those involving the (s+1)st element - these have the form a[s]*((k-1)-product of the first s elements) - and those not involving it - these are the k-products of the first s elements.
Code such that result[i] is the coefficient of Xi (the sum of the (n-i)-products):
int *k_products_1(int *a, int n){
int *new, *old = calloc((n+1)*sizeof(int));
int d, i;
old[0] = 1;
for(d = 1; d <= n; ++d){
new = calloc((n+1)*sizeof(int));
new[0] = a[d-1]*old[0];
for(i = 1; i <= d; ++i){
new[i] = old[i-1] + a[d-1]*old[i];
}
free(old);
old = new;
}
return old;
}
If you only want the sum of the k-products for one k, you can stop the calculation at index n-k, giving an O(n*(n-k)) algorithm - that's good if k >= n/2. To get an O(n*k) algorithm for k <= n/2, you have to organise the coefficient array the other way round, so that result[k] is the coefficient of Xn-k (and stop the calculation at index k if you want only one sum):
int *k_products_2(int *a, int n){
int *new, *old = calloc((n+1)*sizeof(int));
int d, i;
old[0] = 1;
for(d = 1; d <= n; ++d){
new = calloc((n+1)*sizeof(int));
new[0] = 1;
for(i = 1; i <= d; ++i){
new[i] = old[i] + a[d-1]*old[i-1];
}
free(old);
old = new;
}
return old;
}