Open In App

Count number of increasing subsequences of size k

Improve
Improve
Like Article
Like
Save
Share
Report

Given an array arr[] containing n integers. The problem is to count number of increasing subsequences in the array of size k.

Examples: 

Input : arr[] = {2, 6, 4, 5, 7}, 
k = 3
Output : 5
The subsequences of size '3' are:
{2, 6, 7}, {2, 4, 5}, {2, 4, 7},
{2, 5, 7} and {4, 5, 7}.
Input : arr[] = {12, 8, 11, 13, 10, 15, 14, 16, 20},
k = 4
Output : 39

Approach: The idea is to use Dynamic Programming by define 2D matrix, say dp[][]. dp[i][j] stores the count of increasing subsequences of size i ending with element arr[j]. So dp[i][j] can be defined as: 

dp[i][j] = 1, where i = 1 and 1 <= j <= n 
dp[i][j] = sum(dp[i-1][j]), where 1 < i <= k, i <= j <= n and arr[m] < arr[j] for (i-1) <= m < j.

Below is the implementation of above approach: 

C++




// C++ implementation to count number of
// increasing subsequences of size k
#include <bits/stdc++.h>
 
using namespace std;
 
// function to count number of increasing
// subsequences of size k
int numOfIncSubseqOfSizeK(int arr[], int n, int k)
{
    int dp[k][n], sum = 0;
    memset(dp, 0, sizeof(dp));
 
    // count of increasing subsequences of size 1
    // ending at each arr[i]
    for (int i = 0; i < n; i++)
        dp[0][i] = 1;
 
    // building up the matrix dp[][]
    // Here 'l' signifies the size of
    // increasing subsequence of size (l+1).
    for (int l = 1; l < k; l++) {
 
        // for each increasing subsequence of size 'l'
        // ending with element arr[i]
        for (int i = l; i < n; i++) {
 
            // count of increasing subsequences of size 'l'
            // ending with element arr[i]
            dp[l][i] = 0;
            for (int j = l - 1; j < i; j++) {
                if (arr[j] < arr[i])
                    dp[l][i] += dp[l - 1][j];
            }
        }
    }
 
    // sum up the count of increasing subsequences of
    // size 'k' ending at each element arr[i]
    for (int i = k - 1; i < n; i++)
        sum += dp[k - 1][i];
 
    // required number of increasing
    // subsequences of size k
    return sum;
}
 
// Driver program to test above
int main()
{
    int arr[] = { 12, 8, 11, 13, 10, 15, 14, 16, 20 };
    int n = sizeof(arr) / sizeof(arr[0]);
    int k = 4;
 
    cout << "Number of Increasing Subsequences of size "
         << k << " = " << numOfIncSubseqOfSizeK(arr, n, k);
 
    return 0;
}


Java




//Java implementation to count number of
// increasing subsequences of size k
 
class GFG {
 
// function to count number of increasing
// subsequences of size k
    static int numOfIncSubseqOfSizeK(int arr[], int n, int k) {
        int dp[][] = new int[k][n], sum = 0;
 
        // count of increasing subsequences of size 1
        // ending at each arr[i]
        for (int i = 0; i < n; i++) {
            dp[0][i] = 1;
        }
 
        // building up the matrix dp[][]
        // Here 'l' signifies the size of
        // increasing subsequence of size (l+1).
        for (int l = 1; l < k; l++) {
 
            // for each increasing subsequence of size 'l'
            // ending with element arr[i]
            for (int i = l; i < n; i++) {
 
                // count of increasing subsequences of size 'l'
                // ending with element arr[i]
                dp[l][i] = 0;
                for (int j = l - 1; j < i; j++) {
                    if (arr[j] < arr[i]) {
                        dp[l][i] += dp[l - 1][j];
                    }
                }
            }
        }
 
        // sum up the count of increasing subsequences of
        // size 'k' ending at each element arr[i]
        for (int i = k - 1; i < n; i++) {
            sum += dp[k - 1][i];
        }
 
        // required number of increasing
        // subsequences of size k
        return sum;
    }
 
// Driver program to test above
    public static void main(String[] args) {
        int arr[] = {12, 8, 11, 13, 10, 15, 14, 16, 20};
        int n = arr.length;
        int k = 4;
 
        System.out.print("Number of Increasing Subsequences of size "
                + k + " = " + numOfIncSubseqOfSizeK(arr, n, k));
 
    }
}
// This code is contributed by 29AjayKumar


Python3




# Python3 implementation to count number
# of increasing subsequences of size k
import math as mt
 
# function to count number of increasing
# subsequences of size k
def numOfIncSubseqOfSizeK(arr, n, k):
 
    dp = [[0 for i in range(n)]
             for i in range(k)]
              
    # count of increasing subsequences
    # of size 1 ending at each arr[i]
    for i in range(n):
        dp[0][i] = 1
 
    # building up the matrix dp[][]
    # Here 'l' signifies the size of
    # increasing subsequence of size (l+1).
    for l in range(1, k):
 
        # for each increasing subsequence of
        # size 'l' ending with element arr[i]
        for i in range(l, n):
 
            # count of increasing subsequences of
            # size 'l' ending with element arr[i]
            dp[l][i] = 0
            for j in range(l - 1, i):
                if (arr[j] < arr[i]):
                    dp[l][i] += dp[l - 1][j]
             
    # Sum up the count of increasing subsequences
    # of size 'k' ending at each element arr[i]
    Sum = 0
    for i in range(k - 1, n):
        Sum += dp[k - 1][i]
 
    # required number of increasing
    # subsequences of size k
    return Sum
 
# Driver Code
arr = [12, 8, 11, 13, 10,
          15, 14, 16, 20 ]
n = len(arr)
k = 4
 
print("Number of Increasing Subsequences of size",
         k, "=", numOfIncSubseqOfSizeK(arr, n, k))
 
# This code is contributed by
# Mohit kumar 29


C#




// C# implementation to count number of
// increasing subsequences of size k
  
using System;
                     
public class GFG {
  
// function to count number of increasing
// subsequences of size k
    static int numOfIncSubseqOfSizeK(int []arr, int n, int k) {
        int [,]dp = new int[k,n]; int sum = 0;
  
        // count of increasing subsequences of size 1
        // ending at each arr[i]
        for (int i = 0; i < n; i++) {
            dp[0,i] = 1;
        }
  
        // building up the matrix dp[,]
        // Here 'l' signifies the size of
        // increasing subsequence of size (l+1).
        for (int l = 1; l < k; l++) {
  
            // for each increasing subsequence of size 'l'
            // ending with element arr[i]
            for (int i = l; i < n; i++) {
  
                // count of increasing subsequences of size 'l'
                // ending with element arr[i]
                dp[l,i] = 0;
                for (int j = l - 1; j < i; j++) {
                    if (arr[j] < arr[i]) {
                        dp[l,i] += dp[l - 1,j];
                    }
                }
            }
        }
  
        // sum up the count of increasing subsequences of
        // size 'k' ending at each element arr[i]
        for (int i = k - 1; i < n; i++) {
            sum += dp[k - 1,i];
        }
  
        // required number of increasing
        // subsequences of size k
        return sum;
    }
  
// Driver program to test above
    public static void Main() {
        int []arr = {12, 8, 11, 13, 10, 15, 14, 16, 20};
        int n = arr.Length;
        int k = 4;
  
        Console.Write("Number of Increasing Subsequences of size "
                + k + " = " + numOfIncSubseqOfSizeK(arr, n, k));
  
    }
}
// This code is contributed by 29AjayKumar


Javascript




<script>
 
// JavaScript implementation to count number of
// increasing subsequences of size k
 
// function to count number of increasing
// subsequences of size k
    function numOfIncSubseqOfSizeK(arr, n, k)
    {
        let dp = new Array(k), sum = 0;
         
        // Loop to create 2D array using 1D array
        for (let i = 0; i < dp.length; i++) {
            dp[i] = new Array(2);
        }
   
        // count of increasing subsequences of size 1
        // ending at each arr[i]
        for (let i = 0; i < n; i++) {
            dp[0][i] = 1;
        }
   
        // building up the matrix dp[][]
        // Here 'l' signifies the size of
        // increasing subsequence of size (l+1).
        for (let l = 1; l < k; l++) {
   
            // for each increasing subsequence of size 'l'
            // ending with element arr[i]
            for (let i = l; i < n; i++) {
   
                // count of increasing subsequences of size 'l'
                // ending with element arr[i]
                dp[l][i] = 0;
                for (let j = l - 1; j < i; j++) {
                    if (arr[j] < arr[i]) {
                        dp[l][i] += dp[l - 1][j];
                    }
                }
            }
        }
   
        // sum up the count of increasing subsequences of
        // size 'k' ending at each element arr[i]
        for (let i = k - 1; i < n; i++) {
            sum += dp[k - 1][i];
        }
   
        // required number of increasing
        // subsequences of size k
        return sum;
    }
 
// Driver code   
          
        let arr = [12, 8, 11, 13, 10, 15, 14, 16, 20];
        let n = arr.length;
        let k = 4;
   
        document.write("Number of Increasing Subsequences of size "
                + k + " = " + numOfIncSubseqOfSizeK(arr, n, k));
             
</script>


PHP




<?php
// PHP implementation to count
// number of increasing
// subsequences of size k
 
// function to count number
// of increasing subsequences
// of size k
function numOfIncSubseqOfSizeK($arr,
                               $n, $k)
{
    $dp = array(array());
    $sum = 0;
    $dp = array_fill(0, $n + 1, false);
 
    // count of increasing
    // subsequences of size 1
    // ending at each arr[i]
    for ($i = 0; $i < $n; $i++)
        $dp[0][$i] = 1;
 
    // building up the matrix
    // dp[][]. Here 'l' signifies
    // the size of increasing
    // subsequence of size (l+1).
    for ($l = 1; $l < $k; $l++)
    {
 
        // for each increasing
        // subsequence of size 'l'
        // ending with element arr[i]
        for ($i = $l; $i < $n; $i++)
        {
 
            // count of increasing
            // subsequences of size 'l'
            // ending with element arr[i]
            $dp[$l][$i] = 0;
            for ($j = $l - 1; $j < $i; $j++)
            {
                if ($arr[$j] < $arr[$i])
                    $dp[$l][$i] += $dp[$l - 1][$j];
            }
        }
    }
 
    // sum up the count of increasing
    // subsequences of size 'k' ending
    // at each element arr[i]
    for ($i = $k - 1; $i < $n; $i++)
        $sum += $dp[$k - 1][$i];
 
    // required number of increasing
    // subsequences of size k
    return $sum;
}
 
// Driver Code
$arr = array(12, 8, 11, 13,
             10, 15, 14, 16, 20);
$n = sizeof($arr);
$k = 4;
 
echo "Number of Increasing ".
     "Subsequences of size ",
                 $k , " = " ,
     numOfIncSubseqOfSizeK($arr,
                           $n, $k);
 
// This code is contributed
// by akt_mit
?>


Output

Number of Increasing Subsequences of size 4 = 39




Time Complexity: O(kn2). 
Auxiliary Space: O(kn).

Segment Tree Approach

For every element arr[i], we need to search for all arr[i]-1 as these are the elements that can be appended to arr[i] to make increasing subsequence. This is very much similar to COUNT LONGEST INCREASING SUBSEQUENCES. We use a vector of size K for each node in segment Tree signifying the length of LIS of size K ending at node. 

Stepping down the array to smaller numbers with same ordering will reduce the space complexity as well. 

If arr[i] has vector K={1,3,2}, signifies there is   one K=1 length LIS ending at arr[i] 

                                                                        three K=2 length LIS ending at arr[i]

                                                                        two K=3 length LIS ending at arr[i]

If arr[j] is greater than arr[i], then arr[j] can appended after arr[i]. So the vector of arr[j] becomes {1,1,3}. 

The K=1 remains the same since every element itself is a single length(K=1) subsequence. 

We will take subsequences of length K=1 from arr[i] in the K=2 of arr[j] Since all the K=1 increasing subsequences of arr[i] becomes K=2 length increasing subsequences when arr[j] is added to arr[i]. 

Similarly all the K=2 length subsequences of arr[i] becomes K=3 length subsequences for arr[j] as arr[j] gets appended to K=2 subsequences of arr[i]. We are not adding here, because we are calculating ways, not length. 

Simply saying vec_j[K]=vec_i[K-1], where K>1

Below is the implementation of above approach: 

C++




#include <bits/stdc++.h>
using namespace std;
 
vector<vector<long long>>tree; /* vector<long long> represents the number of ways
                                  LIS of size K ending at node can be formed */
 
int RANKER(vector<int>& arr) {
    int n = arr.size();
 
    vector<int> temp = arr;
    sort(temp.begin(), temp.end());
 
    unordered_map<int, int> mpp;
    int mx = 0;
 
    for (int i = 0; i < n; i++) {
        if (mpp.find(temp[i]) == mpp.end()) {
            mpp[temp[i]] = mx;
            mx++;
        }
    }
    for (int i = 0; i < n; i++) {
        arr[i] = mpp[arr[i]];
    }
    return mx;
}
 
vector<long long> summation(vector<long long>& left, vector<long long>& right, int k) {
    // ADD WAYS, REMEMBER NO NEED TO TAKE MAX, WE ARE FINDING WAYS, NOT LENGTH.
    // So each K will contribute to final answer
    vector<long long> res(k + 1, 0);
    for (int i = 1; i <= k; i++) {
        res[i] = left[i] + right[i];
    }
    return res;
}
 
vector<long long> query(int start, int end, int parent, int qstart, int qend, int k) {
    if (end < qstart || qend < start) {
        return vector<long long>(k + 1, 0);
    }
    if (qstart <= start && qend >= end) {
        return tree[parent];
    }
    int mid = (start + end) / 2;
    vector<long long> left = query(start, mid, 2 * parent + 1, qstart, qend, k);
    vector<long long> right = query(mid + 1, end, 2 * parent + 2, qstart, qend, k);
    return summation(left, right, k);
}
 
void update(int start, int end, int parent, int index, vector<long long>& updateThis, int k) {
    if (index < start || index > end) {
        return;
    }
    if (start == end) {
        tree[parent] = summation(updateThis, tree[parent], k);
        return;
    }
    int mid = (start + end) / 2;
    if (index > mid) {
        update(mid + 1, end, 2 * parent + 2, index, updateThis, k);
    }
    else {
        update(start, mid, 2 * parent + 1, index, updateThis, k);
    }
    vector<long long> left = tree[2 * parent + 1];
    vector<long long> right = tree[2 * parent + 2];
    tree[parent] = summation(left, right, k);
    return;
}
 
int numOfIncSubseqOfSizeK(vector<int>& arr, int K) {
    int n = arr.size();
 
    int mx = RANKER(arr);
 
    tree.resize(4 * mx + 1, vector<long long>(K + 1, 0));
 
    for (int i = 0; i < n; i++) {
        vector<long long> Kj(K + 1, 0); // K length ways
        Kj[1] = 1; // K=1 is element itself
       
        if (arr[i] > 0) { // arr[0] cannot be queried, since its the lowest
           
          /* Querying the longest LIS K array where arr[i] can append to*/
            vector<long long> Ki = query(0, mx, 0, 0, arr[i] - 1, K);
 
              for (int k = 2; k <= K; k++) { // As explained before
                Kj[k] = Ki[k - 1];
            }
        }
       
        update(0, mx, 0, arr[i], Kj, K); // update Kj array for arr[i]
    }
    return tree[0][K]; // answer is at kth index of root's K array
}
 
int main() {
    vector<int> arr = { 12, 8, 11, 13, 10, 15, 14, 16, 20 };
    int k = 4;
    cout << "Number of Increasing Subsequences of size "
         << k << " = " << numOfIncSubseqOfSizeK(arr, k);
    return 0;
}
 
// Code by RainX (ABHIJIT ROY, NIT AGARTALA)


Java




// Java program for the above approach
import java.util.*;
 
public class GFG {
    static List<List<Long> > tree
        = new ArrayList<>(); /* List of Lists, where each
                                inner List represents the
                                number of ways
                                 LIS of size K ending at
                                node can be formed */
 
    public static void main(String[] args)
    {
        List<Integer> arr = Arrays.asList(12, 8, 11, 13, 10,
                                          15, 14, 16, 20);
        int k = 4;
        System.out.println(
            "Number of Increasing Subsequences of size " + k
            + " = " + numOfIncSubseqOfSizeK(arr, k));
    }
 
    // Function to convert original array to ranks
    static int RANKER(List<Integer> arr)
    {
        int n = arr.size();
 
        List<Integer> temp = new ArrayList<>(arr);
        temp.sort(Comparator.naturalOrder());
 
        Map<Integer, Integer> mpp = new HashMap<>();
        int mx = 0;
 
        for (int i = 0; i < n; i++) {
            if (!mpp.containsKey(temp.get(i))) {
                mpp.put(temp.get(i), mx);
                mx++;
            }
        }
 
        for (int i = 0; i < n; i++) {
            arr.set(i, mpp.get(arr.get(i)));
        }
 
        return mx;
    }
 
    // Function to add ways of two sets of LIS
    static List<Long> summation(List<Long> left,
                                List<Long> right, int k)
    {
        // ADD WAYS, REMEMBER NO NEED TO TAKE MAX, WE ARE
        // FINDING WAYS, NOT LENGTH. So each K will
        // contribute to the final answer
        List<Long> res = new ArrayList<>(
            Collections.nCopies(k + 1, 0L));
        for (int i = 1; i <= k; i++) {
            res.set(i, left.get(i) + right.get(i));
        }
        return res;
    }
 
    // Function to perform a range query in the segment tree
    static List<Long> query(int start, int end, int parent,
                            int qstart, int qend, int k)
    {
        if (end < qstart || qend < start) {
            return new ArrayList<>(
                Collections.nCopies(k + 1, 0L));
        }
        if (qstart <= start && qend >= end) {
            return tree.get(parent);
        }
        int mid = (start + end) / 2;
        List<Long> left = query(start, mid, 2 * parent + 1,
                                qstart, qend, k);
        List<Long> right = query(
            mid + 1, end, 2 * parent + 2, qstart, qend, k);
        return summation(left, right, k);
    }
 
    // Function to update the segment tree after processing
    // an element
    static void update(int start, int end, int parent,
                       int index, List<Long> updateThis,
                       int k)
    {
        if (index < start || index > end) {
            return;
        }
        if (start == end) {
            tree.set(
                parent,
                summation(updateThis, tree.get(parent), k));
            return;
        }
        int mid = (start + end) / 2;
        if (index > mid) {
            update(mid + 1, end, 2 * parent + 2, index,
                   updateThis, k);
        }
        else {
            update(start, mid, 2 * parent + 1, index,
                   updateThis, k);
        }
        List<Long> left = tree.get(2 * parent + 1);
        List<Long> right = tree.get(2 * parent + 2);
        tree.set(parent, summation(left, right, k));
    }
 
    // Main function to calculate the number of increasing
    // subsequences of size K
    static long numOfIncSubseqOfSizeK(List<Integer> arr,
                                      int K)
    {
        int n = arr.size();
 
        int mx = RANKER(arr);
 
        tree = new ArrayList<>(Collections.nCopies(
            4 * mx + 1, new ArrayList<>(Collections.nCopies(
                            K + 1, 0L))));
 
        for (int i = 0; i < n; i++) {
            List<Long> Kj = new ArrayList<>(
                Collections.nCopies(K + 1, 0L));
            Kj.set(1, 1L);
 
            if (arr.get(i) > 0) {
                List<Long> Ki
                    = query(0, mx, 0, 0, arr.get(i) - 1, K);
 
                for (int k = 2; k <= K; k++) {
                    Kj.set(k, Ki.get(k - 1));
                }
            }
 
            update(0, mx, 0, arr.get(i), Kj, K);
        }
        return tree.get(0).get(
            K); // answer is at kth index of root's K array
    }
}
 
// This code is contributed by Susobhan Akhuli


Python3




from typing import List, Dict
 
tree = []
def RANKER(arr: List[int]) -> int:
    n = len(arr)
    temp = arr.copy()
    temp.sort()
    mpp = {}
    mx = 0
    for i in range(n):
        if temp[i] not in mpp:
            mpp[temp[i]] = mx
            mx += 1
    for i in range(n):
        arr[i] = mpp[arr[i]]
    return mx
 
def summation(left: List[int], right: List[int], k: int) -> List[int]:
    #  ADD WAYS, REMEMBER NO NEED TO TAKE MAX, WE ARE FINDING WAYS, NOT LENGTH.
    # So each K will contribute to final answer
    res = [0] * (k + 1)
    for i in range(1, k+1):
        res[i] = left[i] + right[i]
    return res
 
def query(start: int, end: int, parent: int, qstart: int, qend: int, k: int) -> List[int]:
    if end < qstart or qend < start:
        return [0] * (k + 1)
    if qstart <= start and qend >= end:
        return tree[parent]
    mid = (start + end) // 2
    left = query(start, mid, 2 * parent + 1, qstart, qend, k)
    right = query(mid + 1, end, 2 * parent + 2, qstart, qend, k)
    return summation(left, right, k)
 
def update(start: int, end: int, parent: int, index: int, updateThis: List[int], k: int) -> None:
    if index < start or index > end:
        return
    if start == end:
        tree[parent] = summation(updateThis, tree[parent], k)
        return
    mid = (start + end) // 2
    if index > mid:
        update(mid + 1, end, 2 * parent + 2, index, updateThis, k)
    else:
        update(start, mid, 2 * parent + 1, index, updateThis, k)
    left = tree[2 * parent + 1]
    right = tree[2 * parent + 2]
    tree[parent] = summation(left, right, k)
    return
 
def numOfIncSubseqOfSizeK(arr: List[int], K: int) -> int:
    n = len(arr)
    mx = RANKER(arr)
    global tree
    tree = [[0] * (K + 1) for _ in range(4 * mx + 1)]
    for i in range(n):
        # K length ways
        Kj = [0] * (K + 1)
        # K=1 is element itself
        Kj[1] = 1
         
        # arr[0] cannot be queried, since its the lowest
        if arr[i] > 0:
            # Querying the longest LIS K array where arr[i] can append to
            Ki = query(0, mx, 0, 0, arr[i] - 1, K)
            # As explained before
            for k in range(2, K+1):
                Kj[k] = Ki[k - 1]
                # update Kj array for arr[i]
        update(0, mx, 0, arr[i], Kj, K)
    # answer is at kth index of root's K array
    return tree[0][K]
 
if __name__ == '__main__':
    arr = [12, 8, 11, 13, 10, 15, 14, 16, 20]
    k = 4
    print("Number of Increasing Subsequences of size", k, "=", numOfIncSubseqOfSizeK(arr, k))
 
# This code is contributed by shivhack999


C#




// C# program for the above approach
using System;
using System.Collections.Generic;
using System.Linq;
 
public class GFG
{
    static List<List<long>> tree; /* List<long> represents the number of ways
                                   LIS of size K ending at node can be formed */
 
    static int RANKER(List<int> arr)
    {
        int n = arr.Count;
 
        List<int> temp = new List<int>(arr);
        temp.Sort();
 
        Dictionary<int, int> mpp = new Dictionary<int, int>();
        int mx = 0;
 
        for (int i = 0; i < n; i++)
        {
            if (!mpp.ContainsKey(temp[i]))
            {
                mpp[temp[i]] = mx;
                mx++;
            }
        }
 
        for (int i = 0; i < n; i++)
        {
            arr[i] = mpp[arr[i]];
        }
 
        return mx;
    }
 
    static List<long> Summation(List<long> left, List<long> right, int k)
    {
        // ADD WAYS, REMEMBER NO NEED TO TAKE MAX, WE ARE FINDING WAYS, NOT LENGTH.
        // So each K will contribute to the final answer
        List<long> res = new List<long>(new long[k + 1]);
        for (int i = 1; i <= k; i++)
        {
            res[i] = left[i] + right[i];
        }
        return res;
    }
 
    static List<long> Query(int start, int end, int parent, int qstart, int qend, int k)
    {
        if (end < qstart || qend < start)
        {
            return new List<long>(new long[k + 1]);
        }
 
        if (qstart <= start && qend >= end)
        {
            return tree[parent];
        }
 
        int mid = (start + end) / 2;
        List<long> left = Query(start, mid, 2 * parent + 1, qstart, qend, k);
        List<long> right = Query(mid + 1, end, 2 * parent + 2, qstart, qend, k);
        return Summation(left, right, k);
    }
 
    static void Update(int start, int end, int parent, int index, List<long> updateThis, int k)
    {
        if (index < start || index > end)
        {
            return;
        }
 
        if (start == end)
        {
            tree[parent] = Summation(updateThis, tree[parent], k);
            return;
        }
 
        int mid = (start + end) / 2;
        if (index > mid)
        {
            Update(mid + 1, end, 2 * parent + 2, index, updateThis, k);
        }
        else
        {
            Update(start, mid, 2 * parent + 1, index, updateThis, k);
        }
 
        List<long> left = tree[2 * parent + 1];
        List<long> right = tree[2 * parent + 2];
        tree[parent] = Summation(left, right, k);
        return;
    }
 
    static int NumOfIncSubseqOfSizeK(List<int> arr, int K)
    {
        int n = arr.Count;
 
        int mx = RANKER(arr);
 
        tree = new List<List<long>>(new List<long>[4 * mx + 1].Select(_ => new List<long>(new long[K + 1])));
 
        for (int i = 0; i < n; i++)
        {
            List<long> Kj = new List<long>(new long[K + 1]); // K length ways
            Kj[1] = 1; // K=1 is the element itself
 
            if (arr[i] > 0) // arr[0] cannot be queried, since it's the lowest
            {
                /* Querying the longest LIS K array where arr[i] can append to */
                List<long> Ki = Query(0, mx, 0, 0, arr[i] - 1, K);
 
                for (int k = 2; k <= K; k++) // As explained before
                {
                    Kj[k] = Ki[k - 1];
                }
            }
 
            Update(0, mx, 0, arr[i], Kj, K); // update Kj array for arr[i]
        }
 
        return (int)tree[0][K]; // answer is at the kth index of the root's K array
    }
 
    static void Main()
    {
        List<int> arr = new List<int> { 12, 8, 11, 13, 10, 15, 14, 16, 20 };
        int k = 4;
        Console.WriteLine($"Number of Increasing Subsequences of size {k} = {NumOfIncSubseqOfSizeK(arr, k)}");
    }
}
 
// This code is contributed by Susobhan Akhuli


Javascript




let tree = []; /* array of arrays, where each inner array represents the number of ways
                  LIS of size K ending at node can be formed */
 
function RANKER(arr) {
  let n = arr.length;
   
  let temp = [...arr];
  temp.sort((a, b) => a - b);
   
  let mpp = new Map();
  let mx = 0;
   
  for (let i = 0; i < n; i++) {
    if (!mpp.has(temp[i])) {
      mpp.set(temp[i], mx);
      mx++;
    }
  }
   
  for (let i = 0; i < n; i++) {
    arr[i] = mpp.get(arr[i]);
  }
   
  return mx;
}
 
function summation(left, right, k) {
  // ADD WAYS, REMEMBER NO NEED TO TAKE MAX, WE ARE FINDING WAYS, NOT LENGTH.
  // So each K will contribute to final answer
  let res = new Array(k + 1).fill(0);
  for (let i = 1; i <= k; i++) {
    res[i] = left[i] + right[i];
  }
  return res;
}
 
function query(start, end, parent, qstart, qend, k) {
  if (end < qstart || qend < start) {
    return new Array(k + 1).fill(0);
  }
  if (qstart <= start && qend >= end) {
    return tree[parent];
  }
  let mid = Math.floor((start + end) / 2);
  let left = query(start, mid, 2 * parent + 1, qstart, qend, k);
  let right = query(mid + 1, end, 2 * parent + 2, qstart, qend, k);
  return summation(left, right, k);
}
 
function update(start, end, parent, index, updateThis, k) {
  if (index < start || index > end) {
    return;
  }
  if (start === end) {
    tree[parent] = summation(updateThis, tree[parent], k);
    return;
  }
  let mid = Math.floor((start + end) / 2);
  if (index > mid) {
    update(mid + 1, end, 2 * parent + 2, index, updateThis, k);
  } else {
    update(start, mid, 2 * parent + 1, index, updateThis, k);
  }
  let left = tree[2 * parent + 1];
  let right = tree[2 * parent + 2];
  tree[parent] = summation(left, right, k);
  return;
}
 
function numOfIncSubseqOfSizeK(arr, K) {
    const n = arr.length;
 
    const mx = RANKER(arr);
 
    tree = new Array(4 * mx + 1).fill().map(() => new Array(K + 1).fill(0));
 
    for (let i = 0; i < n; i++) {
        const Kj = new Array(K + 1).fill(0);
        Kj[1] = 1;
       
        if (arr[i] > 0) {
            const Ki = query(0, mx, 0, 0, arr[i] - 1, K);
 
            for (let k = 2; k <= K; k++) {
                Kj[k] = Ki[k - 1];
            }
        }
       
        update(0, mx, 0, arr[i], Kj, K);
    }
    return tree[0][K];
}
 
const arr = [12, 8, 11, 13, 10, 15, 14, 16, 20];
const k = 4;
console.log(`Number of Increasing Subsequences of size ${k} = ${numOfIncSubseqOfSizeK(arr, k)}`);


Output

Number of Increasing Subsequences of size 4 = 39




Time Complexity: O(n*K*logn). For each index, we need to do query(logn) and update in K array(k)
Auxiliary Space: O(kn).



Last Updated : 12 Dec, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads