(Analysis by Benjamin Qi)

Subtask 1: Try all $N!=N\cdot (N-1)\cdots 1$ possible $p$ in lexicographical order, and see if they can produce $h$. In Python, we can use itertools.permutations to do this easily.

Ben's Python code:

def P_to_H(P):
    H = []
    while len(P) > 1:
        if P[0] > P[-1]:
            H.append(P[1])
            P = P[1:]
        else:
            H.append(P[-2])
            P = P[:-1]
    return H
 
 
import itertools
 
 
def solve():
    N = int(input())
    H = list(map(int, input().split()))
    for P in itertools.permutations(range(1, N + 1)):
        if P_to_H(P) == H:
            print(" ".join(map(str, P)))
            return
    print(-1)
 
 
T = int(input())
for _ in range(T):
    solve()

Subtask 2: If we are given the values of $p_1$ and $p_N$, we can uniquely determine the rest of $p$ by going through $h$ one element at a time. In particular, when $N>2$,

and then we can process $h_2,h_3,\dots, h_{N-1}$ similarly. At the end, we should check if $p$ forms a permutation or not and actually produces $h$; if so, we update our answer. The time complexity is $O(N^3)$ per test.

Ben's Python code:

def P_to_H(P):
    H = []
    while len(P) > 1:
        if P[0] > P[-1]:
            H.append(P[1])
            P = P[1:]
        else:
            H.append(P[-2])
            P = P[:-1]
    return H
 
 
def solve():
    N = int(input())
    H = list(map(int, input().split()))
    ans = None
    for l_val in range(1, N + 1):
        for r_val in range(1, N + 1):
            cand = [-1] * N
            l = 0
            r = N - 1
            cand[l] = l_val
            cand[r] = r_val
            for h in H:
                if cand[l] > cand[r]:
                    l += 1
                    cand[l] = h
                else:
                    r -= 1
                    cand[r] = h
            if len(set(cand)) == N and P_to_H(cand) == H:
                if ans is None:
                    ans = cand
                ans = min(ans, cand)
 
    if ans is None:
        print(-1)
        return
    print(" ".join(map(str, ans)))
 
 
T = int(input())
for _ in range(T):
    solve()

Subtask 3: Consider the process of producing $h$ from $p$. Note that the smallest element of $p$, $1$, will never be removed. So when two elements remain in $p$, one must be $1$, and $1$ will be the last element written down. Thus, we must have $h_{N-1}=1$, or else we can output $-1$ and exit. For the remainder of the problem, we will not use the last element of $h$, so we discard the last element of $h$ and assume that $h$ has length $N-2$ going forward.

If the answer is not $-1$, the lexicographically minimum $p$ must satisfy $p_1<p_N$, or else reversing $p$ will give a lexicographically smaller permutation.

Can there be more than one permutation $p$ satisfying $p_1<p_N$ that maps to the same $h$? If we print the mapping from $p$ to $h$ for all $p$ for small $N$ (e.g., $N=4$) using our solution for subtask 1, we observe that all $h$ are distinct. So it seems true if there exists some $p$ that maps to $h$, $p$ must be unique up to reversal.

def P_to_H(P):
    H = []
    while len(P) > 1:
        if P[0] > P[-1]:
            H.append(P[1])
            P = P[1:]
        else:
            H.append(P[-2])
            P = P[:-1]
    return H
 
 
import itertools
 
 
N = 4
for P in itertools.permutations(range(1, N + 1)):
    if P[0] < P[-1]:
        print(P, P_to_H(P)[:-1])

Output:

(1, 2, 3, 4) [3, 2]
(1, 2, 4, 3) [4, 2]
(1, 3, 2, 4) [2, 3]
(1, 3, 4, 2) [4, 3]
(1, 4, 2, 3) [2, 4]
(1, 4, 3, 2) [3, 4]
(2, 1, 3, 4) [3, 1]
(2, 1, 4, 3) [4, 1]
(2, 3, 1, 4) [1, 3]
(2, 4, 1, 3) [1, 4]
(3, 1, 2, 4) [2, 1]
(3, 2, 1, 4) [1, 2]

Looking at the permutations above (or from working out a few cases by hand), we can further observe that

  1. All $N-2$ elements of $h$ must be distinct.
  2. The numbers at the ends of $p$ are precisely those two missing from $h$.

Here's a way to see why these observations are true. If we perform the following operation $N-2$ times, we will always end up writing down a permutation of $p_2\dots p_{N-1}$:

Operation: Choose to do exactly one of the following:

  1. Write down $p'_2$ and remove $p'_1$ from the permutation.
  2. Write down $p'_{n-1}$ and remove $p'_n$ from the permutation.

Once we've determined the numbers at the ends of $p$, we can determine the remainder of $p$ in the same way as subtask 2. In fact, it turns out that as long as all elements of $h$ are distinct, there is some $p$ mapping to it.

Ben's Python code:

def solve():
    N = int(input())
    H = list(map(int, input().split()))
    if H[-1] != 1:
        print(-1)
        return
    H = H[:-1]
    remaining = [False] + [True] * N
    for h in H:
        if not remaining[h]:
            print(-1)
            return
        remaining[h] = False
    ends = [x for x in range(1, N + 1) if remaining[x]]
    ans = [-1] * N
    l, r = 0, N - 1
    ans[l], ans[r] = ends
    for h in H:
        if ans[l] > ans[r]:
            l += 1
            ans[l] = h
        else:
            r -= 1
            ans[r] = h
    print(" ".join(map(str, ans)))
 
 
T = int(input())
for _ in range(T):
    solve()

Chongtian's C++ code:

#include <bits/stdc++.h>
using namespace std;
 
int main() {
	int T;
	cin >> T;
	while (T--) {
		int n;
		cin >> n;
		vector<int> h(n - 1);
		for (int &i : h) cin >> i;
		vector<bool> has(n + 1);
		for (int i : h) has[i] = 1;
		vector<int> not_has;
		for (int i = 1; i <= n; i++) {
			if (!has[i]) { not_has.push_back(i); }
		}
		int cnt_one = count(h.begin(), h.end(), 1);
		if (not_has.size() > 2 || h.back() != 1 ||
		    (not_has.size() == 2 && cnt_one != 2)) {
			cout << -1 << endl;
			continue;
		}
		vector<int> p(n);
		if (not_has.size() == 1) {
			// this must mean 1 is in the corner
			p[0] = 1;
			p[n - 1] = not_has[0];
		} else {
			p[0] = not_has[0];
			p[n - 1] = not_has[1];
		}
		int l = 0, r = n - 1;
		for (int i = 0; i < n - 1; i++) {
			if (p[l] > p[r]) {
				p[++l] = h[i];
			} else {
				p[--r] = h[i];
			}
		}
		for (int i = 0; i < n; i++) {
			if (i) cout << " ";
			cout << p[i];
		}
		cout << "\n";
	}
}

Bonus:

In this problem, we constructed a bijection (one-to-one mapping) between all $N!/2$ line graphs with vertex set $1\dots N$ and all $N!/2$ sequences of length $N-2$ consisting only of $1\dots N$ with no duplicates. More generally, there is a bijection between all $N^{N-2}$ trees with vertex set $1\dots N$ and all $N^{N-2}$ sequences of length $N-2$ consisting only of $1\dots N$ (Prufer sequence). The mapping from trees to sequences is essentially the same as described in this problem; $N-2$ times, take the highest leaf, write down the vertex it is adjacent to, and remove the leaf. Try to figure out the reverse mapping (sequence to trees) on your own.