Analysis: Pogo-Cow, by Brian Dean


This problem is solved by dynamic programming. Let us focus on the best left-to-right solution; the same approach will also find the best right-to-left solution, after which we need to take the better of the two. Let DP[i][j] denote the maximum value we can collect if we start at target i and our next hop lands on target j. We can write this recursively as DP[i][j] = value of ith target + max DP[j][k], where k ranges over all targets such that the distance from j to k is at least as large as the distance from i to j. This formulation involves solving O(N^2) subproblems, each of which takes O(N) time to solve, for a total of O(N^3) time. Unfortunately, O(N^3) is a bit too slow for the limits given in this problem, but we can speed our algorithm up to run in only O(N^2) time by keeping running maximums of the form DP[j][k...], allowing us to solve each subproblem in only O(1) time.

Mark Gordon's solution is below.

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>

using namespace std;

int DP[1010][1010];

int main() {
  freopen("pogocow.in", "r", stdin);
  freopen("pogocow.out", "w", stdout);

  int N; cin >> N;

  vector<pair<int, int> > A(N);
  for(int i = 0; i < N; i++) 
    cin >> A[i].first >> A[i].second;
  sort(A.begin(), A.end());

  int result = 0;
  for(int ii = 0; ii < 2; ii++) {
    for(int i = N - 1; i >= 0; i--) {
      int k = N;
      int val = 0;
      for(int j = 0; j <= i; j++) {
        while(k - 1 > i &&
              A[k - 1].first - A[i].first >= A[i].first - A[j].first) {
          --k;
          val = max(val, A[k].second + DP[k][i]);
        }
        DP[i][j] = val;
      }
      result = max(result, A[i].second + val);
    }
    for(int i = 0; i < N; i++) {
      A[i].first = -A[i].first;
    }
    reverse(A.begin(), A.end());
  }

  cout << result << endl;
  return 0;
}