dp
binary indexed tree
LIS
]
BinarySearch 0522 Increasing Subsequences of Size K
Problem statement
https://binarysearch.com/problems/Increasing-Subsequences-of-Size-K/solutions/961389/
Solution 1
Define by dp[i] is number of subsequenes ending at A[i] which have k terms. Then we can increase k bo one if we use classical O(n^2) dp: the number of ways with k + 1 terms which end with A[j] can be calculated as sum over all dp[i], where i < j, and A[i] < A[j].
Complexity
It is O(n^2 k) for time and O(n) for space.
Code
class Solution:
def solve(self, A, k):
MOD, n = 10 ** 9 + 7, len(A)
dp = [1] * n
for k in range(k - 1):
dp2 = [0] * n
for j in range(n - 1, -1, -1):
for i in range(j):
if A[i] < A[j]:
dp2[j] += dp[i]
dp = [x % MOD for x in dp2]
return sum(dp) % MOD
Solution 2
There is a better solution. The trick is to keep k binary indexed trees. We add element by element, starting from the smallest values and in dp[j][t] we keep number of Increasing subsequences of length j, which ends with A[t] element. When we add each next greater element, we can use our binary indexed trees to quickly find all smaller elements, instead of O(n), we can do it in O(log n) time.
Complexity
It is O(n log n k) for time and O(n*k) for space.
Code
class BIT:
def __init__(self, n):
self.sums = [0] * (n+1)
def update(self, i, delta):
while i < len(self.sums):
self.sums[i] = (self.sums[i] + delta) % (10**9 + 7)
i += i & (-i)
def query(self, i):
res = 0
while i > 0:
res = (res + self.sums[i]) % (10**9 + 7)
i -= i & (-i)
return res
class Solution:
def solve(self, A, k):
n = len(A)
dp = [BIT(n) for i in range(k)]
arr = sorted([(x, i) for i, x in enumerate(A)])
d = {x: i for i, x in enumerate(sorted(A))}
for i in range(n):
idx = d[A[i]]
for j in range(k - 1):
dp[j].update(idx + 1, dp[j + 1].query(idx))
dp[k - 1].update(idx + 1, 1)
return dp[0].query(n)