Dynamic programming solution
State:
dp[i]: the minimum cost to cover all positions from[0, i]. (left shift by 1 to get 0 index)
// if position i is already covered, then dp[i] is the same with dp[i - 1] or 0 if i is 0
dp[i] = i == 0 ? 0 : dp[i - 1];
//if position i is not covered, for all antenna intervals that are on the left side of i,
diff = i - r[j];
dp[i] = Math.min(dp[i], diff + (l[j] - diff <= 0 ? 0 : dp[l[j] - diff - 1]));
Why do we only care about the intervals that are on the left side of i?
There are a few cases in general:
1. trivial case: there is no interval to the right of i. Only considering intervals on left side gives the correct answer.
2. there is at least 1 interval to the right of i. This case has 2 sub-cases:
a. all the remaining uncovered positions (> i) are adjacent with i, i.e, there is a position k > i such that [i + 1, k] are all uncovered, [k + 1, m] are all covered.
for this case, say we extend one of the interval on the right side to cover i with added cost d. Since there must be an extension or no extension needed to acheive:given an interval to left of i, use some cost to make this interval cover i - d. This means instead of extending an interval on the right side of i, we can just give this cost d to an interval on the left side to make i covered, without yielding a worse minCost.
b. there are uncovered positions (> i) that are separated with i by at least 1 interval to the right of i.
for this case, when extending an interval to the right of i to cover i, we'll also possibly cover more initially uncovered positions to the right of this interval. Denote this right side interval as interval[j]; Pick one of these uncovered positions and denote it as k. Notice interval[j] is on the left side of k. So this case is covered when we calculate dp[k] and check all intervals to k's left side.
As a result, for a given uncovered position i, only checking intervals to its left lead to the correct final answer.
Initialization:
dp[i] = i + 1; Need cost of i + 1 in the worst case such that none of the positions in [0, i] is initially covered.
Answer:
dp[m - 1], m is the max position that needs to be covered.
The runtime is O(n * m) and space is O(m).
private static void solve(int q, FastScanner in, PrintWriter out) {
for(int c = 0; c < q; c++) {
int n = in.nextInt(), m = in.nextInt();
int[][] intervals = new int[n][2];
for(int i = 0; i < n; i++) {
int start = in.nextInt() - 1;
int diff = in.nextInt();
intervals[i][0] = start - diff;
intervals[i][1] = start + diff;
}
int[] dp = new int[m];
for(int i = 0; i < m; i++) {
dp[i] = i + 1;
boolean covered = false;
for(int j = 0; j < n; j++) {
if(intervals[j][0] <= i && intervals[j][1] >= i) {
covered = true;
break;
}
}
if(covered) {
dp[i] = i == 0 ? 0 : dp[i - 1];
}
else {
for(int j = 0; j < n; j++) {
if(intervals[j][0] > i) {
continue;
}
int diff = i - intervals[j][1];
dp[i] = Math.min(dp[i], diff + (intervals[j][0] <= diff ? 0 : dp[intervals[j][0] - diff - 1]));
}
}
}
out.println(dp[m - 1]);
}
out.close();
}