package main
import (
"fmt"
"math"
"sort"
)
type Bitset []uint64
func (b Bitset) Set(pos int) {
b[pos/64] |= 1 << (pos % 64)
}
func (b Bitset) Test(pos int) bool {
if pos < 0 || pos/64 >= len(b) {
return false
}
return (b[pos/64] & (1 << (pos % 64))) != 0
}
func (b Bitset) OrShift(other Bitset, shift int) {
wordShift := shift / 64
bitShift := shift % 64
if bitShift == 0 {
for i := 0; i < len(other); i++ {
if i+wordShift < len(b) {
b[i+wordShift] |= other[i]
}
}
} else {
for i := 0; i < len(other); i++ {
if i+wordShift < len(b) {
b[i+wordShift] |= other[i] << bitShift
}
if i+wordShift+1 < len(b) {
b[i+wordShift+1] |= other[i] >> (64 - bitShift)
}
}
}
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func main() {
var n int
if _, err := fmt.Scan(&n); err != nil {
return
}
v := make([]int, 2*n+1)
for i := 1; i <= 2*n; i++ {
fmt.Scan(&v[i])
}
sort.Ints(v[1:])
suffixSum := make([]int, 2*n+2)
for i := 2 * n; i >= 1; i-- {
suffixSum[i] = suffixSum[i+1] + v[i]
}
totalWords := 0
for i := 2*n + 1; i >= 1; i-- {
maxJ := min(n, 2*n-i+1)
for j := 0; j <= maxJ; j++ {
maxS := min(j*50000, suffixSum[i])
totalWords += maxS/64 + 1
}
}
pool := make([]uint64, totalWords)
poolOffset := 0
alloc := func(words int) Bitset {
res := pool[poolOffset : poolOffset+words]
poolOffset += words
return res
}
dp := make([][]Bitset, 2*n+2)
for i := range dp {
dp[i] = make([]Bitset, n+1)
}
dp[2*n+1][0] = alloc(1)
dp[2*n+1][0].Set(0)
for i := 2 * n; i >= 1; i-- {
maxJ := min(n, 2*n-i+1)
for j := 0; j <= maxJ; j++ {
maxS := min(j*50000, suffixSum[i])
words := maxS/64 + 1
dp[i][j] = alloc(words)
if dp[i+1][j] != nil {
copy(dp[i][j], dp[i+1][j])
}
if j > 0 && dp[i+1][j-1] != nil {
dp[i][j].OrShift(dp[i+1][j-1], v[i])
}
}
}
bestMaxPath := int64(math.MaxInt64)
bestK := -1
bestS := -1
sumAll := suffixSum[1]
for k := 2; k <= n+1; k++ {
remJ := n - (k - 1)
if remJ < 0 {
continue
}
prefSum := 0
for m := 1; m <= k-1; m++ {
prefSum += v[m]
}
bs := dp[k+1][remJ]
if bs == nil {
continue
}
limit := min(remJ*50000, suffixSum[k+1])
for s := 0; s <= limit; s++ {
if bs.Test(s) {
S1 := prefSum + s
S2 := sumAll - S1
path1 := int64(v[1]) + int64(S2)
pathn := int64(v[k]) + int64(S1)
maxPath := path1
if pathn > maxPath {
maxPath = pathn
}
if maxPath < bestMaxPath {
bestMaxPath = maxPath
bestK = k
bestS = s
}
}
}
}
inR1 := make([]bool, 2*n+1)
for i := 1; i <= bestK-1; i++ {
inR1[i] = true
}
inR1[bestK] = false
remJ := n - (bestK - 1)
currS := bestS
for i := bestK + 1; i <= 2*n; i++ {
canR2 := false
if dp[i+1][remJ] != nil && dp[i+1][remJ].Test(currS) {
canR2 = true
}
canR1 := false
if remJ > 0 && currS >= v[i] && dp[i+1][remJ-1] != nil && dp[i+1][remJ-1].Test(currS-v[i]) {
canR1 = true
}
if canR1 {
inR1[i] = true
currS -= v[i]
remJ--
} else if canR2 {
inR1[i] = false
} else {
panic("no valid choice")
}
}
var R1, R2 []int
for i := 1; i <= 2*n; i++ {
if inR1[i] {
R1 = append(R1, v[i])
} else {
R2 = append(R2, v[i])
}
}
for i, j := 0, len(R2)-1; i < j; i, j = i+1, j-1 {
R2[i], R2[j] = R2[j], R2[i]
}
for i := 0; i < n; i++ {
if i > 0 {
fmt.Print(" ")
}
fmt.Print(R1[i])
}
fmt.Println()
for i := 0; i < n; i++ {
if i > 0 {
fmt.Print(" ")
}
fmt.Print(R2[i])
}
fmt.Println()
}