Baltic OI 2016 - Swap

Authors: Benjamin Qi, Andi Qu

Approach 1

Complexity: time with memory.

Let the elements of be nodes of a graph and each potential swap be an edge between two nodes. Notice how this graph is a binary tree. We effectively want to perform some swaps to minimize the BFS order of this tree.

Let denote the tree with as the root and and as the subtrees of 's left and right children respectively. We can compute in time.

We can now formulate a basic DP state. Let be the version of node 's subtree after some swaps such that initially and the BFS order of is minimal. Let and be node 's left and right children respectively. The following recurrence holds:

The answer to the problem is thus . If we compute this DP naively, we get a solution that uses memory (since ).

To improve this solution, notice that for some , we have only if is a child of an ancestor of . Since there are only ancestors of and each has at most 2 children, this allows us to cut the time (and memory) complexity down to ! For convenience, we still refer to the original DP state in the rest of this solution.

However, this DP still uses too much memory. There are two things we need to do to fix this:

  • Process the tree in reverse BFS order (i.e. starting from node and working back to node 1). This allows us to free up the memory used by and after we process some node . This cuts the memory used down to , but is still slightly too much.
  • Only compute the states that depends on. For example, the value of is irrelevant if .

These two optimizations save us just enough memory to get AC.

1#include <bits/stdc++.h>
2using namespace std;
3
4int a[200002];
5bool needed[200002][18][2];
6vector<int> dp[200002][18][2], tmp1, tmp2;
7
8void merge(vector<int> &ret, vector<int> &l, vector<int> &r) {
9 for (int i = 0, j = 1; i < l.size(); i += j, j <<= 1) {
10 for (int k = i; k < i + j && k < l.size(); k++) ret.push_back(l[k]);

Approach 2

Some magic DP. See the discussion on CF.

Time Complexity: , can be reduced to .

Memory Complexity:

1#include <bits/stdc++.h>
2using namespace std;
3
4using ll = long long;
5using ld = long double;
6using db = double;
7using str = string; // yay python!
8
9using pi = pair<int,int>;
10using pl = pair<ll,ll>;

Approach 3

Maintain some collection of heaps and compute the sequence in order. I think this is similar to what the official solution does, although I don't completely understand it.

Time Complexity:

Memory Complexity:

1#include <bits/stdc++.h>
2using namespace std;
3
4using ll = long long;
5using ld = long double;
6using db = double;
7using str = string; // yay python!
8
9using pi = pair<int,int>;
10using pl = pair<ll,ll>;

Join the USACO Forum!

Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!

Give Us Feedback on Baltic OI 2016 - Swap!