π₯ The Problem That Looks Like LISβ¦ But Isnβt
Youβre given an array.
Youβre asked to find a non-decreasing subsequence.
Easy, right? Classic LIS problem.
But then comes the twist:
βYou MUST pass through certain checkpoints.β
Now everything changes.
This is no longer a standard LIS problem.
This is a constraint-heavy optimization problem.
π§ Real Problem Statement
You are given an array a[1..N] of positive integers and a set of p checkpoint indices cp1..P.
You need to find a subsequence such that:
It passes through all P checkpoints (each cp[k] must be included)
It is non-decreasing (i.e., a[i] β€ a[j] for valid sequence order)
The total sum is maximized
π₯ Input Format
First line: integer n (size of array)
Second line: integer p (number of checkpoints)
Next n lines: values of array a[i]
Next p lines: checkpoint indices cp[i]
π Constraints
1 β€ n β€ 500
1 β€ p β€ 10
1 β€ a[i] β€ 10^4
1 β€ cp[i] β€ n
π§ͺ Sample Test Cases
Case 1
Input:
5
2
10
20
15
30
40
2
4
Output:
100
π Valid subsequence:
10 β 20 β 30 β 40
Case 2
Input:
4
2
50
40
30
20
1
4
Output:
-1
π Why?
50 β 20 β decreasing β invalid
β οΈ Why This Problem is Tricky
At first glance:
βJust run LIS.β
But hereβs the catch:
- You cannot skip checkpoints
- You must maintain global non-decreasing order
- You must maximize sum, not length
π£ The First Critical Check
Before doing anything, validate checkpoints:
if (a[cp[i]] < a[cp[i-1]])
return -1;
β Why?
If checkpoints themselves are decreasing:
a[cp[i-1]] > a[cp[i]]
Then no valid subsequence exists.
π§ Key Insight (Game Changer)
Break the problem into segments.
π Think Like This:
Start β cp[0] β cp[1] β cp[2] β ... β cp[p-1] β End
Instead of solving globally:
π Solve each segment independently
βοΈ DP Strategy (Core Logic)
For each segment, we use:
dp[i] = maximum sum of non-decreasing subsequence ending at i
π Transition
if (a[j] <= a[i])
dp[i] = max(dp[i], dp[j] + a[i]);
π Constraint Enforcement
We must ensure continuity across segments:
a[i] >= prev_val
Where:
prev_val = value of last checkpoint used
π Full Flow
- Validate checkpoint order
- Process each segment using DP
- Ensure non-decreasing continuity
- Accumulate result
- Process remaining tail
π» Final Code
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, p;
cin >> n >> p;
vector<int> a(n+1);
for (int i = 1; i <= n; i++) cin >> a[i];
vector<int> cp(p);
for (int i = 0; i < p; i++) cin >> cp[i];
// Check if checkpoints themselves are valid
for (int i = 1; i < p; i++) {
if (a[cp[i]] < a[cp[i-1]]) {
cout << -1 << endl;
return 0;
}
}
int prev_idx = 1;
int prev_val = 0;
int total = 0;
for (int k = 0; k < p; k++) {
int L = prev_idx;
int R = cp[k];
// DP for this segment
vector<int> dp(n+1, 0);
for (int i = L; i <= R; i++) {
if (a[i] < prev_val) continue;
dp[i] = a[i];
for (int j = L; j < i; j++) {
if (a[j] <= a[i] && dp[j] > 0) {
dp[i] = max(dp[i], dp[j] + a[i]);
}
}
}
if (dp[R] == 0) {
cout << -1 << endl;
return 0;
}
total += dp[R];
prev_val = a[R];
prev_idx = R + 1;
}
// Handle remaining part after last checkpoint
vector<int> dp(n+1, 0);
for (int i = prev_idx; i <= n; i++) {
if (a[i] < prev_val) continue;
dp[i] = a[i];
for (int j = prev_idx; j < i; j++) {
if (a[j] <= a[i] && dp[j] > 0) {
dp[i] = max(dp[i], dp[j] + a[i]);
}
}
}
int best = 0;
for (int i = prev_idx; i <= n; i++) {
best = max(best, dp[i]);
}
total += best;
cout << total << endl;
return 0;
}
β‘ Complexity
Time: O(NΒ²)
Space: O(N)
Efficient enough for:
N β€ 500
π§ Key Takeaways
- Constraints Change Everything
This is NOT LIS anymore β it's constrained LIS.
- Break Big Problems
Global β Local segments β Combine
- Always Validate Early
Fail fast:
if invalid β return -1
- Max Sum β Max Length
We optimize value, not size.
π― Interview One-Liner
βWe split the array by checkpoints and run constrained LIS with maximum sum using DP.β
π Final Thought
The hardest problems arenβt about writing code.
Theyβre about:
Understanding constraints
Breaking problems smartly
Handling edge cases










