Problem:
Score : 400 points

Problem Statement

A positive integer X is said to be a lunlun number if and only if the following condition is satisfied:

In the base ten representation of X (without leading zeros), for every pair of two adjacent digits, the absolute difference of those digits is at most 1.

For example, 1234, 1, and 334 are lunlun numbers, while none of 31415, 119, or 13579 is.

You are given a positive integer K. Find the K-th smallest lunlun number.

Constraints

1 \leq K \leq 10^5

All values in input are integers.

Input

Input is given from Standard Input in the following format:

K

Output

Print the answer.

Sample Input 1

15

Sample Output 1

23

We will list the 15 smallest lunlun numbers in ascending order:

1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
21,
22,
23.

Thus, the answer is 23.

Sample Input 2

1

Sample Output 2

1

Sample Input 3

13

Sample Output 3

21

Sample Input 4

100000

Sample Output 4

3234566667

Note that the answer may not fit into the 32-bit signed integer type.

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

using System;
using System.IO;
using System.Text;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using static System.Console;
using static System.Math;

namespace AtCoder
{
    public class Tree
    {
        static public long globalCount = -1;
        public string value;
        public long count;
        public List<Tree> nextTreeList;

        public Tree(string value)
        {
            this.count = ++globalCount;
            this.value = value;
            this.nextTreeList = new List<Tree>();
        }
        public void AddNext(string next = null)
        {
            if (next != null)
            {
                this.nextTreeList.Add(new Tree(next));
                return;
            }


            if(value[value.Length-1] - '0' - 1 >= 0)
            {
                this.nextTreeList.Add(new Tree(value + (value[value.Length - 1] - '0' - 1).ToString()));
            }
            this.nextTreeList.Add(new Tree(value + (value[value.Length - 1] - '0').ToString()));
            if (value[value.Length - 1] - '0' + 1 <= 9)
            {
                this.nextTreeList.Add(new Tree(value + (value[value.Length - 1] - '0' + 1).ToString()));

            }
        }
    }

    public class Program
    {
        const long MOD = 1000000007;
        public static void Main(string[] args)
        {
            new Program().Solve(new ConsoleInput(Console.In, ' '));
        }

        public void Solve(ConsoleInput cin)
        {
            long K = cin.ReadLong;
            Tree root = new Tree("0");
            root.AddNext("1");
            root.AddNext("2");
            root.AddNext("3");
            root.AddNext("4");
            root.AddNext("5");
            root.AddNext("6");
            root.AddNext("7");
            root.AddNext("8");
            root.AddNext("9");

            Search(root, K);
        }

        public int Check(Tree tree, long K)
        {
            if (tree.count == K)
            {
                WriteLine(tree.value);
                return 0;
            }
            else
            {
                return -1;
            }
        }

        public int Search(Tree tree, long K)
        {
            List<Tree> tmpTree = tree.nextTreeList;
            for(int i=0; i<tmpTree.Count; i++)
            {
                if(Check(tmpTree[i], K) == 0)
                {
                    return 0;
                }
                else
                {
                    tmpTree[i].AddNext();
                    tmpTree.AddRange(tmpTree[i].nextTreeList);
                }
            }
            return -1;

        }

        const long MAX = 1000000000;
        long[] fac = new long[MAX];
        long[] finv = new long[MAX];
        long[] inv = new long[MAX];
        // テーブルを作る前処理
        void COMinit()
        {
            fac[0] = fac[1] = 1;
            finv[0] = finv[1] = 1;
            inv[1] = 1;
            WriteLine(MAX);
            for (long i = 2; i < MAX; i++)
            {
                if (i % 100000000 == 0)
                    WriteLine(i);
                fac[i] = fac[i - 1] * i % MOD;
                inv[i] = MOD - inv[MOD % i] * (MOD / i) % MOD;
                finv[i] = finv[i - 1] * inv[i] % MOD;
            }
        }
        // 二項係数計算
        long COM(int n, int k)
        {
            if (n < k) return 0;
            if (n < 0 || k < 0) return 0;
            return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
        }


        static bool SameDigits(string str)
        {
            char first = str[0];
            for (var i = 1; i < str.Length; i++)
            {
                if (first == str[i])
                {
                    continue;
                }
                else
                {
                    return false;
                }

            }
            return true;
        }

        static long GcdArray(long[] array)
        {
            var ans = array[0];
            for (var i = 1; i < array.Length; i++)
            {
                ans = Gcd(ans, array[i]);
            }
            return ans;
        }

        static long Gcd(long a, long b)
        {
            var v = new[] { a, b };
            while (v[1] != 0) { v = new[] { v[1], v[0] % v[1] }; }
            return v[0];
        }

        static List<long> GetDivisor(long n)
        {
            List<long> divisor = new List<long>();
            for (long i = 1; i * i <= n; i++)
            {
                if (n % i == 0)
                {
                    divisor.Add(i);
                    if (i != n / i)
                        divisor.Add(n / i);
                }
            }
            divisor.Sort();
            return divisor;

        }

        // 互いに素
        static bool coprime(long a, long b)
        {
            return (Gcd(a, b) == 1);
        }

        static long Lcm(long a, long b)
        {
            return a / Gcd(a, b) * b;
        }

        static bool ChMin<Type>(ref Type a, Type b)
            where Type : IComparable
        {
            if (a.CompareTo(b) > 0)
            {
                a = b;
                return true;
            }
            return false;
        }

        static bool ChMax<Type>(ref Type a, Type b)
            where Type : IComparable
        {
            if (a.CompareTo(b) < 0)
            {
                a = b;
                return true;
            }
            return false;
        }

        public static void RotateRight(IList sequence, int count)
        {
            object tmp = sequence[count - 1];
            sequence.RemoveAt(count - 1);
            sequence.Insert(0, tmp);
        }

        public static IEnumerable<IList> Permutate(IList sequence, int count)
        {
            if (count == 1) yield return sequence;
            else
            {
                for (int i = 0; i < count; i++)
                {
                    foreach (var perm in Permutate(sequence, count - 1))
                        yield return perm;
                    RotateRight(sequence, count);
                }
            }
        }

        private static readonly List<int> facs = new List<int> { 1 };
        private static int Fac(int n)
        {
            for (int i = facs.Count; i <= n; ++i)
            {
                facs.Add((int)(Math.BigMul(facs.Last(), i) % MOD));
            }
            WriteLine(facs[n]);
            return facs[n];
        }
        public static long Ncr(int n, int r)
        {
            WriteLine(n);
            WriteLine(r);
            WriteLine(Fac(n));
            WriteLine(Fac(r) * (long)Fac(n - r));
            return (n < r) ? 0
                 : (n == r) ? 1
                            : Fac(n) / (Fac(r) * (long)Fac(n - r));
        }
    }

    public class ConsoleInput
    {
        private readonly System.IO.TextReader _stream;
        private char _separator = ' ';
        private Queue<string> inputStream;
        public ConsoleInput(System.IO.TextReader stream, char separator = ' ')
        {
            this._separator = separator;
            this._stream = stream;
            inputStream = new Queue<string>();
        }
        public string Read
        {
            get
            {
                if (inputStream.Count != 0) return inputStream.Dequeue();
                string[] tmp = _stream.ReadLine().Split(_separator);
                for (int i = 0; i < tmp.Length; ++i)
                    inputStream.Enqueue(tmp[i]);
                return inputStream.Dequeue();
            }
        }
        public string ReadLine { get { return _stream.ReadLine(); } }
        public int ReadInt { get { return int.Parse(Read); } }
        public long ReadLong { get { return long.Parse(Read); } }
        public double ReadDouble { get { return double.Parse(Read); } }
        public string[] ReadStrArray(long N) { var ret = new string[N]; for (long i = 0; i < N; ++i) ret[i] = Read; return ret; }
        public int[] ReadIntArray(long N) { var ret = new int[N]; for (long i = 0; i < N; ++i) ret[i] = ReadInt; return ret; }
        public long[] ReadLongArray(long N) { var ret = new long[N]; for (long i = 0; i < N; ++i) ret[i] = ReadLong; return ret; }
    }

    // From http://visualstudiomagazine.com/articles/2012/11/01/priority-queues-with-c.aspx
    public class PriorityQueue<T> where T : IComparable<T>
    {
        private List<T> data;

        public PriorityQueue()
        {
            this.data = new List<T>();
        }

        public void Enqueue(T item)
        {
            data.Add(item);
            int ci = data.Count - 1; // child index; start at end
            while (ci > 0)
            {
                int pi = (ci - 1) / 2; // parent index
                if (data[ci].CompareTo(data[pi]) >= 0)
                    break; // child item is larger than (or equal) parent so we're done
                T tmp = data[ci];
                data[ci] = data[pi];
                data[pi] = tmp;
                ci = pi;
            }
        }

        public T Dequeue()
        {
            // assumes pq is not empty; up to calling code
            int li = data.Count - 1; // last index (before removal)
            T frontItem = data[0];   // fetch the front
            data[0] = data[li];
            data.RemoveAt(li);

            --li; // last index (after removal)
            int pi = 0; // parent index. start at front of pq
            while (true)
            {
                int ci = pi * 2 + 1; // left child index of parent
                if (ci > li)
                    break;  // no children so done
                int rc = ci + 1;     // right child
                if (rc <= li && data[rc].CompareTo(data[ci]) < 0) // if there is a rc (ci + 1), and it is smaller than left child, use the rc instead
                    ci = rc;
                if (data[pi].CompareTo(data[ci]) <= 0)
                    break; // parent is smaller than (or equal to) smallest child so done
                T tmp = data[pi];
                data[pi] = data[ci];
                data[ci] = tmp; // swap parent and child
                pi = ci;
            }
            return frontItem;
        }

        public T Peek()
        {
            T frontItem = data[0];
            return frontItem;
        }

        public int Count()
        {
            return data.Count;
        }

        public override string ToString()
        {
            string s = "";
            for (int i = 0; i < data.Count; ++i)
                s += data[i].ToString() + " ";
            s += "count = " + data.Count;
            return s;
        }

        public bool IsConsistent()
        {
            // is the heap property true for all data?
            if (data.Count == 0)
                return true;
            int li = data.Count - 1; // last index
            for (int pi = 0; pi < data.Count; ++pi)
            { // each parent index
                int lci = 2 * pi + 1; // left child index
                int rci = 2 * pi + 2; // right child index

                if (lci <= li && data[pi].CompareTo(data[lci]) > 0)
                    return false; // if lc exists and it's greater than parent then bad.
                if (rci <= li && data[pi].CompareTo(data[rci]) > 0)
                    return false; // check the right child too.
            }
            return true; // passed all checks
        }
        // IsConsistent

    }
}