using System;
using System.Collections.Generic;

namespace diverta2019
{
	struct OrderElement{
		public int x;
		public int y;
		public OrderElement(int i_x,int i_y){
			x = i_x;
			y = i_y;
		}
	}
	class Program
	{
		static void Main(string[] args)
		{
			// 入力
			int N = int.Parse(Console.ReadLine());
			int[] A = Array.ConvertAll(Console.ReadLine().Split(' '), int.Parse);
			// 処理
			// (A0-A1)-(A2-A3)-...としていけば、正の数を+として残すことができる。
			// A0-(A1-A2-A3-...)としていけば、1つを除けば、全て+として残すことも可能。
			// つまり
			// (1)全て正の場合、A1を最小値としてA0-(A1-A2-...)とすればよい
			// (2)全て負の場合、A0を最大値としてA0-A1-A2-...とすればよい
			// (3)上記以外の場合、A[0]~A[k]までを正、A[k+1]~A[N-1]までを負として、A[0]-(A[k+1]-A[1]-A[2]-...-A[k])-A[k+2]-A[k+3]-...-A[N-1]とすればよい
			// 順番も簡単に導ける
			// 正の数の個数を調べる
			if(N==2){
				// こいつは例外
				if (A[0]>A[1])
				{
					Console.WriteLine(A[0]-A[1]);
					Console.WriteLine("{0} {1}", A[0], A[1]);
				}else
				{
					Console.WriteLine(A[1] - A[0]);
					Console.WriteLine("{0} {1}", A[1], A[0]);
				}
				return;
			}
			int plusCount = 0;
			for (int i = 0; i < N; i++)
			{
				if (A[i]>=0)
				{
					plusCount++;
				}
			}
			// (1)~(3)の場合分け
			List<OrderElement> order = new List<OrderElement>(N);
			int M;
			if (plusCount==N)
			{
				// (1)の場合
				int minIndex = 0;
				for (int i = 0; i < N; i++)
				{
					// 最小値の位置を求める
					if (A[minIndex]>A[i])
					{
						minIndex = i;
					}
				}
				// 順番を記録しながら、最小値を計算
				int xMinusY = A[minIndex];
				int index = 0;
				for (int count = 0; count < N - 2; index++)
				{
					if (index == minIndex)
					{
						continue;
					}else
					{
						order.Add(new OrderElement(xMinusY,A[index]));
						xMinusY = xMinusY - A[index];
						count++;
					}
				}
				// 最後の逆転するやつ
				order.Add(new OrderElement(A[index],xMinusY));
				xMinusY = A[index] - xMinusY;
				M = xMinusY;
			}else if (plusCount==0)
			{
				// (2)の場合
				int maxIndex = 0;
				// 最大値の場所を求める
				for (int i = 0; i < N; i++)
				{
					if (A[maxIndex]<A[i])
					{
						maxIndex = i;
					}
				}
				// A[maxIndex]-A[0]-...を格納していく
				int xMinusY = A[maxIndex];
				for (int i = 0; i < N; i++)
				{
					if (i==maxIndex)
					{
						continue;
					}else
					{
						order.Add(new OrderElement(xMinusY, A[i]));
						xMinusY = xMinusY - A[i];
					}
				}
				M = xMinusY;
			}else
			{
				// (3)の場合
				int firstPlusIndex = N;// 初めて正である場所
				int firstMinusIndex = N;// 初めて負である場所
				for (int i = 0; i < N; i++)
				{
					if (A[i]>=0 && firstPlusIndex==N)
					{
						firstPlusIndex = i;
					}else if(A[i]<0 && firstMinusIndex==N)
					{
						firstMinusIndex = i;
					}
					if (firstPlusIndex!=N && firstMinusIndex!=N)
					{
						break;
					}
				}
				// 計算式に基づき、順番を格納していく
				int xMinusY = A[firstMinusIndex];
				// 正の値の処理
				for (int i = 0; i < N; i++)
				{
					if (i!=firstPlusIndex && A[i]>=0)
					{
						order.Add(new OrderElement(xMinusY, A[i]));
						xMinusY = xMinusY - A[i];
					}
				}
				// firstPlusIndexの処理
				order.Add(new OrderElement(A[firstPlusIndex], xMinusY));
				xMinusY = A[firstPlusIndex] - xMinusY;
				// 残りの負の値の処理
				for (int i = 0; i < N; i++)
				{
					if (i!=firstMinusIndex && A[i]<0)
					{
						order.Add(new OrderElement(xMinusY, A[i]));
						xMinusY = xMinusY - A[i];
					}
				}
				M = xMinusY;
			}
			// 結果出力
			Console.WriteLine(M);
			foreach (OrderElement elm in order)
			{
				Console.WriteLine("{0} {1}", elm.x, elm.y);
			}
		}
	}
}


Measured memory_bytes: 28488