PROBLEM LINK:
Practice
Contest: Division 1
Contest: Division 2
Contest: Division 3
Contest: Division 4
Author: shubham_6105
Tester: sushil2006
Editorialist: iceknight1093
DIFFICULTY:
Simple
PREREQUISITES:
Greedy
PROBLEM:
You’re given the price of a stock at N time instants, denoted P_1, \ldots, P_N; as well as a transaction cost K.
Find the maximum number of winning trades possible, where each trade corresponds to buying/selling at one index and then selling/buying respectively at a later index.
A trade is winning if its selling price minus its buying price minus K is positive.
If a trade is done with indices i and j, no other buy/sell operations are allowed between indices i to j, inclusive.
EXPLANATION:
A trade involving indices i and j is profitable if and only if either P_i - P_j - K \gt 0 or P_j - P_i - K \gt 0 (depending on whether we sell at i and buy at j or vice versa.)
Note that at most one of those inequalities can possibly be true; and we can in fact reduce the condition to the single inequality |P_i - P_j| - K \gt 0.
Now, suppose we perform m profitable trades.
Let the i-th of these be involving indices x_i and y_i (with x_i \lt y_i).
Then, since trades cannot overlap with each other, we must have
Now, observe that it’s optimal to choose y_1 to be as small as possible.
That is, let r_1 be the smallest index such that there exists an index l_1 \lt r_1 for which the trade (l_1, r_1) is winning.
Then, it’s optimal to choose y_1 = r_1.
This is because we certainly must have y_1 \ge r_1 by definition of r_1; and if y_1 \gt r_1 we can then replace (x_1, y_1) with (l_1, r_1) to obtain the same number of trades (every following trade remains valid.)
Let’s now try to find the index r_1; so that we know what the first trade is.
Let’s iterate i = 1, 2, 3, \ldots and check if i = r_1 is possible.
For this to work, there must be an index j \lt i such that |P_i - P_j| - K \gt 0.
Observe that if any element P_j satisfies this, then certainly either the minimum element or the maximum element before index i will too.
So, we only need to know the minimum and maximum elements before index i; and if either of them allows for a profitable trade, then we have i = r_1.
If not, update the minimum/maximum elements with P_i, and move on to checking for index i+1.
This allows us to find the index r_1 in linear time.
Observe that after finding r_1, we essentially have to solve the same problem on the remaining suffix of P, starting from index r_1 + 1 instead.
That is, the next trade must be done with the smallest index r_2 \gt r_1 such that a winning trade is possible with index r_2 and some other index in [r_1+1, r_2-1], and so on after r_2.
Just as we found r_1 in linear time, we can find r_2 in linear time, then r_3, and so on.
Note that as long as we break out of the loop immediately upon finding one r_i (or equivalently, reset the min/max so far), each index will only need to be processed once; so the overall complexity is linear.
TIME COMPLEXITY:
\mathcal{O}(N) per testcase.
CODE:
Editorialist's code (PyPy3)
for _ in range(int(input())):
n, k = map(int, input().split())
a = list(map(int, input().split()))
ans = 0
mn, mx = 10**10, 0
for x in a:
mn = min(mn, x)
mx = max(mx, x)
if mx - mn - k > 0:
ans += 1
mn, mx = 10**10, 0
print(ans)