Problem:
Score : 400 points

Problem Statement

Find the largest integer that can be formed with exactly N matchsticks, under the following conditions:

Every digit in the integer must be one of the digits A_1, A_2, ..., A_M (1 \leq A_i \leq 9).

The number of matchsticks used to form digits 1, 2, 3, 4, 5, 6, 7, 8, 9 should be 2, 5, 5, 4, 5, 6, 3, 7, 6, respectively.

Constraints

All values in input are integers.

2 \leq N \leq 10^4

1 \leq M \leq 9

1 \leq A_i \leq 9

A_i are all different.

There exists an integer that can be formed by exactly N matchsticks under the conditions.

Input

Input is given from Standard Input in the following format:

N M
A_1 A_2 ... A_M

Output

Print the largest integer that can be formed with exactly N matchsticks under the conditions in the problem statement.

Sample Input 1

20 4
3 7 8 4

Sample Output 1

777773

The integer 777773 can be formed with 3 + 3 + 3 + 3 + 3 + 5 = 20 matchsticks, and this is the largest integer that can be formed by 20 matchsticks under the conditions.

Sample Input 2

101 9
9 8 7 6 5 4 3 2 1

Sample Output 2

71111111111111111111111111111111111111111111111111

The output may not fit into a 64-bit integer type.

Sample Input 3

15 3
5 4 6

Sample Output 3

654

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

using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.IO;
using System.Text.RegularExpressions;
using System.Text;
using System.Diagnostics;
using System.Globalization;
using static System.Math;

namespace D
{
	class Program
	{
		// variables
		int N;
		int M;
		int[] A;
		readonly int[] cost = { 0, 2, 5, 5, 4, 5, 6, 3, 7, 6 };

		void Run(string[] args)
		{
			// main program
			N = Int;
			M = Int;
			A = MakeArray(M, i => Int);
			dp = MakeArray(N + 1, M + 1, (i, j) => BigInteger.MinusOne);
			PrintLine(Solve(N, 0));
		}

		BigInteger[,] dp;
		
		// methods
		BigInteger Solve(int numOfMatches, int aIndex)
		{
			if (aIndex == A.Length) return BigInteger.MinusOne;
			if (numOfMatches == 0) return BigInteger.Zero;
			if (0 > numOfMatches) return BigInteger.MinusOne;
			if (dp[numOfMatches, aIndex] != BigInteger.MinusOne) return dp[numOfMatches, aIndex];

			return dp[numOfMatches, aIndex] = BigInteger.Max(
				10 * Solve(numOfMatches - cost[A[aIndex]], 0) + A[aIndex],
				Solve(numOfMatches, aIndex + 1)
			);
		}



		// utilities
		static void Main(string[] args)
		{
			new Program().Run(args);
#if DEBUG
			Console.Write("Press any key...");
			Console.ReadKey();
#endif
		}

		/// <summary>
		/// Make an array
		/// </summary>
		/// <typeparam name="T">type of element</typeparam>
		/// <param name="count">number of elements</param>
		/// <param name="input">element generator</param>
		/// <returns>array</returns>
		static T[] MakeArray<T>(int count, Func<int, T> input)
		{
			var array = new T[count];
			for (var i = 0; i < count; ++i)
			{
				array[i] = input(i);
			}
			return array;
		}
		/// <summary>
		/// Make a 2-dimensional array
		/// </summary>
		/// <typeparam name="T">type of element</typeparam>
		/// <param name="count1">size of first dimension</param>
		/// <param name="count2">size of second dimension</param>
		/// <param name="input">element generator</param>
		/// <returns>2-dimensional array</returns>
		static T[,] MakeArray<T>(int count1, int count2, Func<int, int, T> input)
		{
			var array = new T[count1, count2];
			for (var i = 0; i < count1; ++i)
			{
				for (var j = 0; j < count2; ++j)
				{
					array[i, j] = input(i, j);
				}
			}
			return array;
		}
		/// <summary>
		/// Make a 3-dimensional array
		/// </summary>
		/// <typeparam name="T">type of element</typeparam>
		/// <param name="count1">size of first dimension</param>
		/// <param name="count2">size of second dimension</param>
		/// <param name="count3">size of third dimension</param>
		/// <param name="input">element generator</param>
		/// <returns>3-dimensional array</returns>
		static T[,,] MakeArray<T>(int count1, int count2, int count3, Func<int, int, int, T> input)
		{
			var array = new T[count1, count2, count3];
			for (var i = 0; i < count1; ++i)
			{
				for (var j = 0; j < count2; ++j)
				{
					for (var k = 0; k < count3; ++k)
					{
						array[i, j, k] = input(i, j, k);
					}
				}
			}
			return array;
		}

		/// <summary>
		/// Output any value.
		/// </summary>
		/// <typeparam name="T">type of value.</typeparam>
		/// <param name="value">value</param>
		[DebuggerNonUserCode]
		static void Print<T>(T value)
		{
			Console.Write(value);
		}
		/// <summary>
		/// Output any value on a line.
		/// </summary>
		/// <typeparam name="T">type of value</typeparam>
		/// <param name="value">value</param>
		[DebuggerNonUserCode]
		static void PrintLine<T>(T value)
		{
			Console.WriteLine(value);
		}

		/// <summary>
		/// Input a word
		/// </summary>
		static string Word
		{
			[DebuggerNonUserCode]
			get
			{
				char c;
				while (char.IsWhiteSpace(c = (char)Console.Read()))
				{
					continue;
				}

				var builder = new StringBuilder();
				do
				{
					builder.Append(c);
				}
				while (!char.IsWhiteSpace(c = (char)Console.Read()));

				return builder.ToString();
			}
		}
		/// <summary>
		/// Input a line
		/// </summary>
		static string Line
		{
			[DebuggerNonUserCode]
			get
			{
				return Console.ReadLine();
			}
		}
		/// <summary>
		/// Input bool
		/// </summary>
		static bool Bool
		{
			[DebuggerNonUserCode]
			get
			{
				return bool.Parse(Word);
			}
		}
		/// <summary>
		/// Input char
		/// </summary>
		static char Char
		{
			[DebuggerNonUserCode]
			get
			{
				return char.Parse(Word);
			}
		}
		/// <summary>
		/// Input byte
		/// </summary>
		static byte Byte
		{
			[DebuggerNonUserCode]
			get
			{
				return byte.Parse(Word);
			}
		}
		/// <summary>
		/// Input ushort
		/// </summary>
		static ushort UShort
		{
			[DebuggerNonUserCode]
			get
			{
				return ushort.Parse(Word);
			}
		}
		/// <summary>
		/// Input uint
		/// </summary>
		static uint UInt
		{
			[DebuggerNonUserCode]
			get
			{
				return uint.Parse(Word);
			}
		}
		/// <summary>
		/// Input ulong
		/// </summary>
		static ulong ULong
		{
			[DebuggerNonUserCode]
			get
			{
				return ulong.Parse(Word);
			}
		}
		/// <summary>
		/// Input sbyte
		/// </summary>
		static sbyte SByte
		{
			[DebuggerNonUserCode]
			get
			{
				return sbyte.Parse(Word);
			}
		}
		/// <summary>
		/// Input short
		/// </summary>
		static short Short
		{
			[DebuggerNonUserCode]
			get
			{
				return short.Parse(Word);
			}
		}
		/// <summary>
		/// Input int
		/// </summary>
		static int Int
		{
			[DebuggerNonUserCode]
			get
			{
				return int.Parse(Word);
			}
		}
		/// <summary>
		/// Input long
		/// </summary>
		static long Long
		{
			[DebuggerNonUserCode]
			get
			{
				return long.Parse(Word);
			}
		}
		/// <summary>
		/// Input decimal
		/// </summary>
		static decimal Decimal
		{
			[DebuggerNonUserCode]
			get
			{
				return decimal.Parse(Word);
			}
		}
		/// <summary>
		/// Input variable length integer
		/// </summary>
		static BigInteger Integer
		{
			[DebuggerNonUserCode]
			get
			{
				return BigInteger.Parse(Word);
			}
		}
		/// <summary>
		/// Input float
		/// </summary>
		static float Float
		{
			[DebuggerNonUserCode]
			get
			{
				return float.Parse(Word);
			}
		}
		/// <summary>
		/// Input double
		/// </summary>
		static double Double
		{
			[DebuggerNonUserCode]
			get
			{
				return double.Parse(Word);
			}
		}

		/// <summary>
		/// Input hex int
		/// </summary>
		static int Hex
		{
			[DebuggerNonUserCode]
			get
			{
				return int.Parse(Word, NumberStyles.HexNumber);
			}
		}
		/// <summary>
		/// Input hex int
		/// </summary>
		static int HexInt
		{
			[DebuggerNonUserCode]
			get
			{
				return Hex;
			}
		}
		/// <summary>
		/// Input hex long
		/// </summary>
		static long HexLong
		{
			[DebuggerNonUserCode]
			get
			{
				return long.Parse(Word, NumberStyles.HexNumber);
			}
		}
		/// <summary>
		/// Input variable length hex integer
		/// </summary>
		static BigInteger HexInteger
		{
			[DebuggerNonUserCode]
			get
			{
				return BigInteger.Parse(Word, NumberStyles.HexNumber);
			}
		}

		/// <summary>
		/// Union-find tree
		/// </summary>
		class UnionFind : UnionFind<Unit, UnitOp>
		{
			/// <param name="count">number of elements</param>
			public UnionFind(int count) : base(count)
			{ }
		}

		/// <summary>
		/// Union-find tree
		/// </summary>
		class UnionFind<TPotential, TPotentialOp>
			where TPotentialOp : struct, IAddable<TPotential>
		{
			/// <summary>
			/// parent indices
			/// </summary>
			readonly int[] Parent;

			/// <summary>
			/// tree rank
			/// </summary>
			readonly int[] Rank;

			/// <summary>
			/// potential
			/// </summary>
			readonly TPotential[] DiffPotential;

			/// <param name="count">number of elements</param>
			public UnionFind(int count)
			{
				Parent = MakeArray(count, i => i);
				Rank = MakeArray(count, i => 0);
				DiffPotential = MakeArray(count, i => default(TPotentialOp).Zero);
			}

			/// <summary>
			/// Get root element
			/// </summary>
			/// <param name="x">element index</param>
			/// <returns>root element index of <c>x</c></returns>
			public int Root(int x)
			{
				if (Parent[x] == x)
				{
					return x;
				}
				else
				{
					var root = Root(Parent[x]);
					DiffPotential[x] = default(TPotentialOp).Add(DiffPotential[x], DiffPotential[Parent[x]]);
					return Parent[x] = root;
				}
			}

			/// <summary>
			/// Get whether two elements belong to the same set.
			/// </summary>
			/// <param name="x">first element index</param>
			/// <param name="y">second element index</param>
			/// <returns>whether two elements belong to the same set</returns>
			public bool Same(int x, int y)
				=> Root(x) == Root(y);


			/// <summary>
			/// Unite two elements
			/// </summary>
			/// <param name="x">first element index</param>
			/// <param name="y">second element index</param>
			public bool Unite(int x, int y)
				=> Unite(x, y, default(TPotentialOp).Zero);

			/// <summary>
			/// Unite two elements
			/// </summary>
			/// <param name="x">first element index</param>
			/// <param name="y">second element index</param>
			/// <param name="potential">potential from <c>x</c> to <c>y</c></param>
			public bool Unite(int x, int y, TPotential potential)
			{
				potential = default(TPotentialOp).Add(potential, Potential(x));
				potential = default(TPotentialOp).Subtract(potential, Potential(y));
				x = Root(x);
				y = Root(y);

				if (x == y) return false;

				if (Rank[x] < Rank[y])
				{
					// Join x to y
					Parent[x] = y;
					DiffPotential[x] = default(TPotentialOp).Negate(potential);
				}
				else
				{
					// Join y to x
					Parent[y] = x;
					if (Rank[x] == Rank[y]) ++Rank[x];
					DiffPotential[y] = potential;
				}
				return true;
			}

			/// <summary>
			/// Get potential difference from root.
			/// </summary>
			/// <param name="x">element index</param>
			/// <returns>potential difference between the element and the root</returns>
			public TPotential Potential(int x)
			{
				Root(x);
				return DiffPotential[x];
			}

			/// <summary>
			/// Get potential difference between two element.
			/// </summary>
			/// <param name="x">first element index</param>
			/// <param name="y">second element index</param>
			/// <returns>potential difference between two element</returns>
			public TPotential Diff(int x, int y)
				=> default(TPotentialOp).Subtract(Potential(y), Potential(x));
		}

		struct Unit
		{ }
		struct UnitOp : IDividable<Unit>
		{
			public Unit Divide(Unit x, Unit y) => default(Unit);
			public Unit One => default(Unit);
			public Unit Multiply(Unit x, Unit y) => default(Unit);
			public Unit Zero => default(Unit);
			public Unit Negate(Unit x) => default(Unit);
			public Unit Add(Unit x, Unit y) => default(Unit);
		}
		struct IntOp : IDividable<int>
		{
			public int Zero => 0;
			public int One => 1;
			public int Negate(int x) => -x;
			public int Add(int x, int y) => x + y;
			public int Multiply(int x, int y) => x * y;
			public int Divide(int x, int y) => x / y;
		}
		struct LongOp : IDividable<long>
		{
			public long Zero => 0L;
			public long One => 1L;
			public long Negate(long x) => -x;
			public long Add(long x, long y) => x + y;
			public long Multiply(long x, long y) => x * y;
			public long Divide(long x, long y) => x / y;
		}
		struct FloatOp : IDividable<float>
		{
			public float Zero => 0.0F;
			public float One => 1.0F;
			public float Negate(float x) => -x;
			public float Add(float x, float y) => x + y;
			public float Multiply(float x, float y) => x * y;
			public float Divide(float x, float y) => x / y;
		}
		struct DoubleOp : IDividable<double>
		{
			public double Zero => 0.0;
			public double One => 1.0;
			public double Negate(double x) => -x;
			public double Add(double x, double y) => x + y;
			public double Multiply(double x, double y) => x * y;
			public double Divide(double x, double y) => x / y;
		}
	}

	interface IDividable<T> : IMultipliable<T>
	{
		T Divide(T x, T y);
	}
	interface IMultipliable<T> : IAddable<T>
	{
		T One { get; }
		T Multiply(T x, T y);
	}
	interface IAddable<T>
	{
		T Zero { get; }
		T Negate(T x);
		T Add(T x, T y);
	}

	static class OperationExtensions
	{
		public static T Subtract<T, TOp>(this TOp op, T x, T y)
			where TOp : struct, IAddable<T>
		{
			return default(TOp).Add(x, default(TOp).Negate(y));
		}
		public static T Sum<T, TOp>(this TOp op, params T[] items)
			where TOp : struct, IAddable<T>
		{
			var sum = default(TOp).Zero;
			foreach (var item in items)
				sum = default(TOp).Add(sum, item);
			return sum;
		}
		public static T Product<T, TOp>(this TOp op, params T[] items)
			where TOp : struct, IMultipliable<T>
		{
			var sum = default(TOp).One;
			foreach (var item in items)
				sum = default(TOp).Multiply(sum, item);
			return sum;
		}
	}

}