Fibonacci sum of a subset with all elements <= k

Given an array of n elements, the task is to find the fibonacci sum of a subset of the array where every element of the subset <= k.
Precisely, find F(Ai1) + F(Ai2) + F(Ai3) + … + F(Aix)), where (Ai1, Ai2, …, Aix) <= K and 1 <= (i1, i2, …, ix) <= n. Here, F(i) is the ith Fibonacci number

Examples :

Input : arr = {1, 2, 3, 4, 2, 7}
        Query 1 : K = 2
        Query 2 : K = 6
Output : 3
         8

Explanation :
In Query 1, the subset {1, 2, 2} is such a subset where all the elements in the subset are <= k i.e <= 2 in this case. The Fibonacci sum of the subset = F(1) + F(2) + F(2) = 1 + 1 + 1 = 3

In Query 2, the subset {1, 2, 3, 4, 2} is such a subset where all the elements in the subset are <= k i.e <= 6 in this case. The Fibonacci sum of the subset = F(1) + F(2) + F(3) + F(4) + F(2) = 1 + 1 + 2 + 3 + 1 = 8

Solve this using two different querying techniques, namely :
1) Online Querying,
2) Offline Querying



In both these methods, the only common step is the generation of the nth Fibonacci number.For an efficient technique to generate the nth Fibonacci number using this.

This method of generating the Fibonacci numbers is common to both querying techniques. Now, look at how to use these Fibonacci numbers that are generated using each of these two techniques.

Method 1 (Online Querying) :
In this technique, process the queries as they arrive. First of all, sort the array in increasing order. After getting a query for a particular k, use binary search on this sorted array to find the last index where the value of the array is & <= k. Let’s call this position x.

Now, since the array is sorted,

For all i <= x, a[i] <= x
i.e
a[i] <= a[x] for all i ∈ [1, x]

So, the subset to focus at is A1, A2, A3, ….Ax in the sorted array A, and Fibonacci sum is : F(A1)+F(A2)+F(A3)+…+F(Ax)

Use Prefix sum arrays to efficiently find the sum of the subset A1, A2, A3, ….Ax.

If prefixFibSum[i] stores the Fibonacci sum till the ith index of the sorted array A, then, the Fibonacci sum of subset of the array from 1 to x, is prefixFibSum[x]

Thus, Fibonacci Sum of Subset[1…x] = prefixFibSum[x], prefixFibSum[x] can be calculated as follows :
prefixFibSum[x] = prefixFibSum[x – 1] + A[x]th Fibonacci number, where, A[x] is the array element at xth index of the array.

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program to find fibonacci sum of 
// subarray where all elements <= k
#include <bits/stdc++.h>
  
using namespace std;
  
// Helper function that multiplies 2 matrices
// F and M of size 2*2, and puts the multiplication
// result back to F[][]
void multiply(int F[2][2], int M[2][2])
{
    int x = F[0][0] * M[0][0] + F[0][1] * M[1][0];
    int y = F[0][0] * M[0][1] + F[0][1] * M[1][1];
    int z = F[1][0] * M[0][0] + F[1][1] * M[1][0];
    int w = F[1][0] * M[0][1] + F[1][1] * M[1][1];
  
    F[0][0] = x;
    F[0][1] = y;
    F[1][0] = z;
    F[1][1] = w;
}
  
/* Helper function that calculates F[][]
   raise to the power n and puts the 
   result in F[][]  */
void power(int F[2][2], int n)
{
    int i;
    int M[2][2] = { { 1, 1 }, { 1, 0 } };
  
    // n - 1 times multiply the 
    // matrix to {{1, 0}, {0, 1}}
    for (i = 2; i <= n; i++)
        multiply(F, M);
}
  
// Returns the nth fibonacci number
int fib(int n)
{
    int F[2][2] = { { 1, 1 }, { 1, 0 } };
    if (n == 0)
        return 0;
    power(F, n - 1);
  
    return F[0][0];
}
  
int findLessThanK(int arr[], int n, int k)
{
    // find first index which is > k 
    // using lower_bound
    return (lower_bound(arr, arr + n, k + 1) 
                        - arr);
}
  
// Function to build Prefix Fibonacci Sum
int* buildPrefixFibonacciSum(int arr[], int n)
{
    // Allocate memory to prefix 
    // fibonacci sum array
    int* prefixFibSum = new int[n];
  
    // Traverse the array from 0 to n - 1,
    // when at the ith index then we calculate 
    // the a[i]th fibonacci number and calculate
    // the fibonacci sum till the ith index as
    // the sum of fibonacci sum till index i - 1 
    // and the a[i]th fibonacci number
    for (int i = 0; i < n; i++) 
    {
        int currFibNumber = fib(arr[i]);
        if (i == 0) {
            prefixFibSum[i] = currFibNumber;
        }
        else {
            prefixFibSum[i] = prefixFibSum[i - 1] 
                              + currFibNumber;
        }
    }
    return prefixFibSum;
}
  
// Return the answer for each query
int processQuery(int arr[], int prefixFibSum[], 
                 int n, int k)
{
  
    // index stores the index till where
    // the array elements are less than k
    int lessThanIndex = findLessThanK(arr, n, k);
  
    if (lessThanIndex == 0)
        return 0;
    return prefixFibSum[lessThanIndex - 1];
}
  
// Driver Code
int main()
{
    int arr[] = { 1, 2, 3, 4, 2, 7 };
    int n = sizeof(arr) / sizeof(arr[0]);
  
    // sort the array arr
    sort(arr, arr + n);
  
    // Build the prefix fibonacci sum array
    int* prefixFibSum = 
         buildPrefixFibonacciSum(arr, n);
  
    // query array stores q queries
    int query[] = { 2, 6 };
    int q = sizeof(query) / sizeof(query[0]);
  
    for (int i = 0; i < q; i++) {
        int k = query[i];
        int ans = 
            processQuery(arr, prefixFibSum, n, k);
          
        cout << "Query  " << i + 1 << " : "
             << ans << endl;
    }
    return 0;
}

chevron_right


Output:

Query  1 : 3
Query  2 : 8

Time Complexity : O(nlogn + qlogn)



Method 2 (Offline Querying) :
In offline querying, store the queries and calculate the answer for each query in a specific order and store and output the result of the queries in the original specified order.

Store each query as a pair of integers where the first member of the pair is the query parameter K for that query and the second member of the pair is the index at which the query occurs originally.
E.g. If queries are following :
query 1 : K = 13;
query 2 : K = 3;
query 3 : K = 8;
then, store query 1 as where 13 is the value of K for that query and 1 is the index specifying that it is the 1st query, similarly query 2 and query 3 are represented as and respectively.

Once, all individual queries are represented as pairs of integers sort the array of query pairs on the basis on K in increasing fashion.
E.g. the above queries after sorting will look like {,, }.

Idea behind sorting queries :
The main idea behind sorting the queries is that when there are elements of a subset which are less than k for some query qi then for all queries qj where i < j and thus Ki <= Kj these elements are present so if the array of elements and the queries(sorted by K) both are sorted, then maintain two pointers one on the array and the other on the queries array.

i, pointing to ith index of the array,
j, pointing to jth index of the queries array

Then, consider the following Pseudo Code :

while (i <= query[j].K) {
     fibonacciSum  = fibonacciSum + a[i]th Fibonacci number
     i = i + 1
}

So, while the elements in the subset are less than or equal to the current query pair’s first member (i.e K), keep on advancing to the next element while adding the required Fibonacci number to the current sum. Once the current element becomes greater than the parameter K of the current query store the current value of sum in the auxiliary array named ans of size q (i.e number of queries) at the index pointed by the 2nd member of the current query’s pair (i.e the original index at which the current query occurs).

ans[query[j].original index] = current value of fibonacciSum

At the end, print the ans array, which stores the result of all the queries in the order in which they were originally present.

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program to find fibonacci sum of 
// subarray where all elements <= k
#include <bits/stdc++.h>
  
using namespace std;
  
// structure where K is the query parameter
// and original index is the index where the 
// query was originally present at.
struct offlineQuery {
    int K, originalIndex;
};
  
// function tp compare queries
bool cmp(offlineQuery q1, offlineQuery q2)
{
    return q1.K < q2.K;
}
  
/* Helper function that multiplies 2 matrices
  F and M of size 2*2, and puts the multiplication 
  result back to F[][] */
void multiply(int F[2][2], int M[2][2])
{
    int x = F[0][0] * M[0][0] + F[0][1] * M[1][0];
    int y = F[0][0] * M[0][1] + F[0][1] * M[1][1];
    int z = F[1][0] * M[0][0] + F[1][1] * M[1][0];
    int w = F[1][0] * M[0][1] + F[1][1] * M[1][1];
  
    F[0][0] = x;
    F[0][1] = y;
    F[1][0] = z;
    F[1][1] = w;
}
  
/* Helper function that calculates F[][] raise
   to the power n and puts the result in F[][]  */
void power(int F[2][2], int n)
{
    int i;
    int M[2][2] = { { 1, 1 }, { 1, 0 } };
  
    // n - 1 times multiply the 
    // matrix to {{1, 0}, {0, 1}}
    for (i = 2; i <= n; i++)
        multiply(F, M);
}
  
// Returns the nth fibonacci number
int fib(int n)
{
    int F[2][2] = { { 1, 1 }, { 1, 0 } };
    if (n == 0)
        return 0;
    power(F, n - 1);
  
    return F[0][0];
}
  
// Return the answer for each query
int* processQuery(int arr[], int queries[], 
                  int n, int q)
{
    // build offline queries where each query
    // is of type offlineQuery which stores
    // both K and original Index of the query
    // in the queries array
    offlineQuery* offlineQueries = 
                  new offlineQuery[q];
  
    // Allocate memory to store ans of each query
    int* ans = new int[q];
  
    for (int i = 0; i < q; i++) {
        int original_index = i;
        int K = queries[i];
        offlineQueries[i].K = K;
        offlineQueries[i].originalIndex = 
                          original_index;
    }
  
    // sort offlineQueries[]
    sort(offlineQueries, offlineQueries + q, cmp);
  
    // i is pointing to the current position
    // array arr fibonacciSum store the 
    // fibonacciSum till ith index
    int i = 0, fibonacciSum = 0;
      
    for (int j = 0; j < q; j++) 
    {
        int currK = offlineQueries[j].K;
        int currQueryIndex = 
            offlineQueries[j].originalIndex;
  
        // keep insering elements to subset
        // while elements are less than 
        // current query's K value
        while (i < n && arr[i] <= currK) 
        {
            fibonacciSum += fib(arr[i]);
            i++;
        }
  
        // store the current value of
        // fibonacci sum in the array ans
        // which stores results for the
        // queries in the original order
        ans[currQueryIndex] = fibonacciSum;
    }
  
    return ans;
}
  
// Driver Code
int main()
{
    int arr[] = { 1, 2, 3, 4, 2, 7 };
    int n = sizeof(arr) / sizeof(arr[0]);
  
    // sort the array arr
    sort(arr, arr + n);
  
    // query array stores q queries
    int queries[] = { 2, 10, 6 };
    int q = sizeof(queries) / sizeof(queries[0]);
  
    // res stores the result of each query
    int* res = processQuery(arr, queries, n, q);
  
    for (int i = 0; i < q; i++) {
        int ans = res[i];
        cout << "Query  " << i + 1 << " : "
             << ans << endl;
    }
    return 0;
}

chevron_right


Output:

Query  1 : 3
Query  2 : 21
Query  3 : 8

Time Complexity : O(nlogn + qlogq)



My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.