← Home
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()
}