The goal of this problem is to minimize a function f(y) describing the total cost of manure transport if the teleporter endpoint is located at position y. Since f(y) has a piecewise linear structure, we do this by scaning y forward and tracing out f(y), pausing at each breakpoint to adjust the current slope of f(y) in an appropriate way, and maintaining a running minimum as we go. There are only O(N) breakpoints so after sorting them in O(NlogN) time we can scan through and trace out f(y) in just O(N) time.
Although the high-level algorithmic picture above is relatively straightforward, it takes a bit of mathematical effort to figure out where all the breakpoints in f(y) need to go -- that is, at which value of y, and how much the slope changes at each breakpoint. Note that the total transport distance f(y) can be broken down into the transport distance for each pile i,
f(y)=∑Ni=1fi(y),
where fi(y)=min(|ai−bi|,|ai−0|+|bi−y|) represents the cost incurred only for transporting pile i (the first part represents the transportation cost if moved directly, and the second part if teleported). Each of the fi's are reasonably simple functions of y. After a bit of mathematical wrangling, we can deduce that the fi's have the following shapes:
In terms of breakpoints these functions contribute to f(y), for example if |ai|≥|ai−bi|, then there are no breakpoints in fi(y) at all -- the entire contribution of fi(y) is to shift f(y) up by |ai−bi|. In another example case, if ai<0 and ai≥bi, then fi has three breakpoints which contribute to f(y): at y=0 the slope of fi(y) (and hence also of f) decreases by 1, at y=b it increases by +2, and at y=2b it decreases by 1.
My code below uses a map to store the slope changes at all the different breakpoints of f, after which it scans across these in sorted order of y and simply traces out f(y), keeping track of the minimum value it attains.
#include <iostream> #include <fstream> #include <map> #include <algorithm> using namespace std; int N; map<int,int> slopechg; // slopechg[t] is how much the slope of f(y) changes when y=t int main(void) { ifstream fin ("teleport.in"); ofstream fout ("teleport.out"); long long current_f = 0, slope_f = 0, current_y = -2000000000; fin >> N; for (int i=0; i<N; i++) { int a, b; fin >> a >> b; current_f += abs(a-b); // Now add any slope change breakpoints... if (abs(a) > abs(a-b)) continue; slopechg[b]+=2; if (a<b && a<0) { slopechg[0]--; slopechg[2*b]--; } if (a<b && a>=0) { slopechg[2*b-2*a]--; slopechg[2*a]--; } if (a>=b && a<0) { slopechg[2*b-2*a]--; slopechg[2*a]--; } if (a>=b && a>=0) { slopechg[0]--; slopechg[2*b]--; } } // Now scan y forward and apply slope changes to trace out f(y), keeping track of min long long min_f = current_f; for (auto p : slopechg) { int new_y = p.first, delta_slope = p.second; current_f += slope_f * (new_y - current_y); current_y = new_y; slope_f += delta_slope; min_f = min(min_f, current_f); } fout << min_f << "\n"; return 0; }