Problem:
Score : 800 points

Problem Statement

Niwango has N cards, numbered 1,2,\ldots,N.
He will now arrange these cards in a row.

Niwango wants to know if there is a way to arrange the cards while satisfying all the N conditions below.
To help him, determine whether such a way exists. If the answer is yes, also find the lexicographically smallest such arrangement.

To the immediate right of Card 1 (if any) is NOT Card a_1.

To the immediate right of Card 2 (if any) is NOT Card a_2.

\vdots

To the immediate right of Card N (if any) is NOT Card a_N.

Constraints

2 \leq N \leq 10^{5}

1 \leq a_i \leq N

a_i \neq i

Input

Input is given from Standard Input in the following format:

N
a_1 a_2 \ldots a_N

Output

If no arrangements satisfy the conditions, print -1. If such arrangements exist, print the lexicographically smallest such arrangement, in the following format:

b_1 b_2 \ldots b_N

Here, b_i represents the i-th card from the left.

Sample Input 1

4
2 3 4 1

Sample Output 1

1 3 2 4

The arrangement (1,2,3,4) is lexicographically smaller than (1,3,2,4), but is invalid, since it violates the condition "to the immediate right of Card 1 is not Card 2."

Sample Input 2

2
2 1

Sample Output 2

-1

If no arrangements satisfy the conditions, print -1.

Sample Input 3

13
2 3 4 5 6 7 8 9 10 11 12 13 12

Sample Output 3

1 3 2 4 6 5 7 9 8 10 12 11 13

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Numerics;
using System.Threading.Tasks;
using static System.Console;
using static System.Math;
using static Func;
class Z { static void Main() => new K(); }
class K
{
	int F => int.Parse(Str);
	long FL => long.Parse(Str);
	int[] G => Strs.Select(int.Parse).ToArray();
	uint[] GU => Strs.Select(uint.Parse).ToArray();
	decimal[] GD => Strs.Select(decimal.Parse).ToArray();
	long[] GL => Strs.Select(long.Parse).ToArray();
	string Str => ReadLine();
	string[] Strs => Str.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
	static ulong One(int k) => 1ul << k;
	static ulong All(int k) => One(k) - 1;
	static bool Has(ulong s, int k) => (s & One(k)) != 0;
	const int MOD = 1000000007;
	public K()
	{
		SetOut(new StreamWriter(OpenStandardOutput()) { AutoFlush = false });
		Solve();
		Out.Flush();
	}
	void Solve()
	{
		var t = Calc(F, G.Select(x => x - 1).ToArray());
		WriteLine(t == null ? "-1" : string.Join(" ", t.Select(i => i + 1)));
	}
	int[] Calc(int N, int[] a)
	{
		if (N == 2) return null;
		var from = new int[N];
		for (var i = 0; i < N; i++) from[a[i]]++;
		var ans = new int[N];
		var set = new SortedSet<int>();
		for (var i = 0; i < N; i++) set.Add(i);
		Action<int> fix;
		{
			var i0 = 0;
			fix = x => { if (!set.Contains(x)) throw new Exception(); ans[i0++] = x; set.Remove(x); };
		}
		Func<int, int> next = ng =>
		{
			var x = set.Min;
			if (x == ng)
			{
				set.Remove(x);
				var y = set.Min;
				set.Add(x);
				return y;
			}
			return x;
		};
		var list = new MultiSet();
		foreach (var c in from) list.Add(c);
		for (var i = 0; i + 1 < N; i++)
		{
			if (list.Max == N - i - 1)
			{
				fix(set.First(j => from[j] == N - i - 1));
				while (set.Count > 0) fix(set.Min);
				if (i + 1 < N && a[ans[i]] == ans[i + 1])
				{
					var t = ans[i + 1];
					ans[i + 1] = ans[i + 2];
					ans[i + 2] = t;
				}
				break;
			}
			var x = next(i == 0 ? -1 : a[ans[i - 1]]);
			if (set.Count == 3)
			{
				var t = set.ToList();
				t.Remove(x);
				var y = t[0];
				if (set.Contains(y) && t[1] == a[y] && y != a[y] && a[a[y]] == y)
				{
					if (i > 0) t.Remove(a[ans[i - 1]]);
					x = t.Min();
				}
			}
			fix(x);
			if (set.Contains(a[x])) list.Decrement(from[a[x]]--);
			list.Remove(from[x]);
		}
		if (set.Count > 0) fix(set.Min);
		return ans;
	}
}
class MultiSet
{
	readonly Dictionary<int, int> cnt = new Dictionary<int, int>();
	readonly SortedSet<int> keys = new SortedSet<int>();
	public int Max => keys.Max;
	public MultiSet() { }
	public void Add(int x)
	{
		if (!cnt.ContainsKey(x))
		{
			cnt[x] = 1;
			keys.Add(x);
		}
		else cnt[x]++;
	}
	public void Remove(int x)
	{
		if (!keys.Contains(x)) throw new Exception();
		if (cnt[x] == 1)
		{
			keys.Remove(x);
			cnt.Remove(x);
		}
		else cnt[x]--;
	}
	public void Decrement(int x)
	{
		Remove(x);
		Add(x - 1);
	}
}
static class Func
{
	public const int Inf = 1073741789;
	public const long InfL = 4011686018427387913L;
	public static T[] ConstantArray<T>(int n, T val) { var a = new T[n]; for (var i = 0; i < n; i++) a[i] = val; return a; }
	public static T[,] ConstantArray<T>(int n, int m, T val) { var a = new T[n, m]; for (var i = 0; i < n; i++) for (var j = 0; j < m; j++) a[i, j] = val; return a; }
	public static T[,,] ConstantArray<T>(int n, int m, int l, T val) { var a = new T[n, m, l]; for (var i = 0; i < n; i++) for (var j = 0; j < m; j++) for (var k = 0; k < l; k++) a[i, j, k] = val; return a; }
	public static T[] MakeArray<T>(int n, Func<int, T> f) { var a = new T[n]; for (var i = 0; i < n; i++) a[i] = f(i); return a; }
	public static T[,] MakeArray<T>(int n, int m, Func<int, int, T> f) { var a = new T[n, m]; for (var i = 0; i < n; i++) for (var j = 0; j < m; j++) a[i, j] = f(i, j); return a; }
	public static T[,,] MakeArray<T>(int n, int m, int l, Func<int, int, int, T> f) { var a = new T[n, m, l]; for (var i = 0; i < n; i++) for (var j = 0; j < m; j++) for (var k = 0; k < l; k++) a[i, j, k] = f(i, j, k); return a; }
	public static T[] Recurse<T>(int n, T a0, Func<int, T, T> f) { var a = new T[n]; a[0] = a0; for (var i = 1; i < n; i++) a[i] = f(i, a[i - 1]); return a; }
	public static T[] Accumulate<T>(IList<T> a, T zero, Func<T, T, T> f) { var s = new T[a.Count + 1]; s[0] = zero; for (var i = 0; i < a.Count; i++) s[i + 1] = f(s[i], a[i]); return s; }
	public static int FirstBinary(int min, int max, Predicate<int> pred)
	{
		while (min < max)
		{
			var mid = (min + max) / 2;
			if (pred(mid)) max = mid;
			else min = mid + 1;
		}
		return min;
	}
	public static long GCD(long a, long b)
	{
		var n = (ulong)Abs(a); var m = (ulong)Abs(b);
		if (n == 0) return (long)m; if (m == 0) return (long)n;
		int zm = 0, zn = 0;
		while ((n & 1) == 0) { n >>= 1; zn++; }
		while ((m & 1) == 0) { m >>= 1; zm++; }
		while (m != n)
		{
			if (m > n) { m -= n; while ((m & 1) == 0) m >>= 1; }
			else { n -= m; while ((n & 1) == 0) n >>= 1; }
		}
		return (long)n << Min(zm, zn);
	}
	public static long Mod(long a, long mod) => (a % mod + mod) % mod;
	public static long Inverse(long a, long mod) => Mod(SolveLinear(Mod(a, mod), mod)[0], mod);
	public static long Pow(long a, long b, long mod)
	{
		var p = 1L;
		var x = a;
		while (b > 0)
		{
			if ((b & 1) == 1) p = (p * x) % mod;
			b >>= 1;
			x = (x * x) % mod;
		}
		return p;
	}
	public static long[] SolveLinear(long n, long m)
	{
		var A = new long[,] { { n < 0 ? -1 : 1, 0 }, { 0, m < 0 ? -1 : 1 } };
		n = Abs(n); m = Abs(m);
		while (m > 0)
		{
			long q = n / m, r = n % m;
			n = m; m = r;
			for (var i = 0; i < 2; i++)
			{
				var x = A[i, 1];
				A[i, 1] = A[i, 0] - q * x;
				A[i, 0] = x;
			}
		}
		return new long[] { A[0, 0], A[1, 0] };
	}
	public static int CombineHashCodes(int h1, int h2) => (((h1 << 5) + h1) ^ h2);
	public static int[] GetFact(int lim, int mod)
	{
		var f = new int[lim];
		f[0] = 1;
		for (var i = 1; i < lim; i++) f[i] = (int)((long)f[i - 1] * i % mod);
		return f;
	}
	public static int[] GetInvFact(int lim, int mod)
	{
		var fc = 1;
		for (var i = 2; i < lim; i++) fc = (int)((long)fc * i % mod);
		return GetInvFact(lim, fc, mod);
	}
	// GetInvFact(n, (n-1)! mod p, p) gives {1, 1/2, ..., 1/(n-1)!} mod p
	public static int[] GetInvFact(int lim, int fc_of_lim_m_1, int mod)
	{
		var ifc = new int[lim];
		ifc[lim - 1] = (int)Inverse(fc_of_lim_m_1, mod);
		for (var i = lim - 1; i >= 1; i--) ifc[i - 1] = (int)((long)ifc[i] * i % mod);
		return ifc;
	}
	public static Comparison<T> DefaultComparison<T>() => (x, y) => Comparer<T>.Default.Compare(x, y);
	public static Comparison<T> ToComparison<T>(this IComparer<T> comp) => comp == null ? DefaultComparison<T>() : (x, y) => comp.Compare(x, y);
}
class PriorityQueue<T> : IEnumerable<T>, ICollection, IEnumerable, ICloneable
{
	Comparison<T> comp;
	List<T> list;
	public int Count { get; private set; } = 0;
	public bool IsEmpty => Count == 0;
	public PriorityQueue(IEnumerable<T> source) : this((Comparison<T>)null, 0, source) { }
	public PriorityQueue(int capacity = 4, IEnumerable<T> source = null) : this((Comparison<T>)null, capacity, source) { }
	public PriorityQueue(IComparer<T> comp, IEnumerable<T> source) : this(comp.ToComparison(), source) { }
	public PriorityQueue(IComparer<T> comp, int capacity = 4, IEnumerable<T> source = null) : this(comp.ToComparison(), source) { list.Capacity = capacity; }
	public PriorityQueue(Comparison<T> comp, IEnumerable<T> source) : this(comp, 0, source) { }
	public PriorityQueue(Comparison<T> comp, int capacity = 4, IEnumerable<T> source = null) { this.comp = comp ?? Func.DefaultComparison<T>(); list = new List<T>(capacity); if (source != null) foreach (var x in source) Enqueue(x); }
	/// <summary>
	/// add an item
	/// this is an O(log n) operation
	/// </summary>
	/// <param name="x">item</param>
	public void Enqueue(T x)
	{
		var pos = Count++;
		list.Add(x);
		while (pos > 0)
		{
			var p = (pos - 1) / 2;
			if (comp(list[p], x) <= 0) break;
			list[pos] = list[p];
			pos = p;
		}
		list[pos] = x;
	}
	/// <summary>
	/// return the minimum element and remove it
	/// this is an O(log n) operation
	/// </summary>
	/// <returns>the minimum</returns>
	public T Dequeue()
	{
		var value = list[0];
		var x = list[--Count];
		list.RemoveAt(Count);
		if (Count == 0) return value;
		var pos = 0;
		while (pos * 2 + 1 < Count)
		{
			var a = 2 * pos + 1;
			var b = 2 * pos + 2;
			if (b < Count && comp(list[b], list[a]) < 0) a = b;
			if (comp(list[a], x) >= 0) break;
			list[pos] = list[a];
			pos = a;
		}
		list[pos] = x;
		return value;
	}
	/// <summary>
	/// look at the minimum element
	/// this is an O(1) operation
	/// </summary>
	/// <returns>the minimum</returns>
	public T Peek() => list[0];
	public IEnumerator<T> GetEnumerator() { var x = (PriorityQueue<T>)Clone(); while (x.Count > 0) yield return x.Dequeue(); }
	void CopyTo(Array array, int index) { foreach (var x in this) array.SetValue(x, index++); }
	public object Clone() { var x = new PriorityQueue<T>(comp, Count); x.Count = Count; x.list.AddRange(list); return x; }
	public void Clear() { list = new List<T>(); Count = 0; }
	public void TrimExcess() => list.TrimExcess();
	/// <summary>
	/// check whether item is in this queue
	/// this is an O(n) operation
	/// </summary>
	public bool Contains(T item) => list.Contains(item);
	IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
	void ICollection.CopyTo(Array array, int index) => CopyTo(array, index);
	bool ICollection.IsSynchronized => false;
	object ICollection.SyncRoot => this;
}