Problem:
Score : 400 points

Problem Statement

In some other world, today is Christmas.

Mr. Takaha decides to make a multi-dimensional burger in his party. A level-L burger (L is an integer greater than or equal to 0) is the following thing:

A level-0 burger is a patty.

A level-L burger (L \geq 1) is a bun, a level-(L-1) burger, a patty, another level-(L-1) burger and another bun, stacked vertically in this order from the bottom.

For example, a level-1 burger and a level-2 burger look like BPPPB and BBPPPBPBPPPBB (rotated 90 degrees), where B and P stands for a bun and a patty.

The burger Mr. Takaha will make is a level-N burger. Lunlun the Dachshund will eat X layers from the bottom of this burger (a layer is a patty or a bun). How many patties will she eat?

Constraints

1 \leq N \leq 50

1 \leq X \leq ( the total number of layers in a level-N burger )

N and X are integers.

Input

Input is given from Standard Input in the following format:

N X

Output

Print the number of patties in the bottom-most X layers from the bottom of a level-N burger.

Sample Input 1

2 7

Sample Output 1

4

There are 4 patties in the bottom-most 7 layers of a level-2 burger (BBPPPBPBPPPBB).

Sample Input 2

1 1

Sample Output 2

0

The bottom-most layer of a level-1 burger is a bun.

Sample Input 3

50 4321098765432109

Sample Output 3

2160549382716056

A level-50 burger is rather thick, to the extent that the number of its layers does not fit into a 32-bit integer.

Solution in C# (Mono-mcs 6.8.0.105) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Windows;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Atcoder
{
    public class Program
    {
        private static long mod = 1000000007;
        private static long max = 999999999999;

        static void Main(string[] args)
        {
            var r = ReadSplit();
            var n = r[0].Int();
            var x = r[1].Long();
            long p = 1;
            long b = 0;
            var pl = new long[n + 1];
            var bl = new long[n + 1];
            var sl = new long[n + 1];
            pl[0] = 1;
            bl[0] = 0;
            sl[0] = 1;
            for (int i =1; i <= n; i++)
            {
                p = p * 2 + 1;
                b = b * 2 + 2;
                pl[i] = p;
                bl[i] = b;
                sl[i] = p + b;
            }

            long tmp = x;
            long now = n;
            var j = 0;
            long ans = 0;
            if (x == 1)
            {
                WriteRead(0);
                return;
            }
            while (true)
            { 
                if (sl[j] >= tmp)
                {
                    if (j == 0)
                    {
                        break;
                    }
                    if (sl[now] / 2 >= tmp)
                    {
                        tmp = tmp - 1;
                        if (tmp == 0)
                        {
                            break;
                        }
                        now--;
                        if (now == 0)
                        {
                            ans++;
                            break;
                        }
                    }
                    else
                    {
                        if (sl[j] - 1 == tmp)
                        {
                            ans += pl[j];
                            break;
                        }
                        tmp = tmp - sl[j - 1] - 2;
                        if (tmp < 0)
                        {
                            ans += pl[j - 1];
                            break;
                        }
                        else
                        {
                            ans += pl[j - 1] + 1;
                        }
                        if (tmp <= 0)
                        {
                            break;
                        }
                        now--;
                    }
                    j = 0;
                }
                else
                {
                    j++;
                }
            }
            WriteRead(ans);
        }

        public static string Read()
        {
            return Console.ReadLine();
        }

        public static string[] ReadSplit()
        {
            return Console.ReadLine().Split(' ');
        }

        public static void WriteRead(object str)
        {
            Console.WriteLine(str);
            Read();
        }

        public static void Write(object str)
        {
            Console.WriteLine(str);
        }

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

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

        /*優先度付きキュー*/
        class PriorityQueue<T> where T : IComparable<T>
        {
            public readonly T[] Array;
            public readonly bool Greater;
            public int Count { get; private set; } = 0;

            public PriorityQueue(int capacity, bool greater = true)
            {
                this.Array = new T[capacity];
                this.Greater = greater;
            }

            public void Enqueue(T item)
            {
                this.Array[this.Count] = item;
                this.Count += 1;
                this.UpHeap();
            }

            public T Dequeue()
            {
                // 先頭要素を末尾にして再構成
                this.Swap(0, this.Count - 1);
                this.Count -= 1;
                this.DownHeap();

                return this.Array[this.Count];
            }


            private void UpHeap()
            {
                var n = this.Count - 1;
                while (n != 0)
                {
                    // 親要素の座標
                    var parent = (n - 1) / 2;

                    if (this.Compare(this.Array[n], this.Array[parent]) > 0)
                    {
                        this.Swap(n, parent);
                        n = parent;
                    }
                    else
                    {
                        break;
                    }
                }
            }

            private void DownHeap()
            {
                var parent = 0;
                while (true)
                {
                    var child = 2 * parent + 1;
                    if (child > this.Count - 1) break;

                    if (child < this.Count - 1 && this.Compare(this.Array[child], this.Array[child + 1]) < 0)
                    {
                        // 左より右の子のほうが大きい値の場合、右を入れ替え対象にする
                        child += 1;
                    }

                    if (this.Compare(this.Array[parent], this.Array[child]) < 0)
                    {
                        this.Swap(parent, child);
                        parent = child;
                    }
                    else
                    {
                        break;
                    }
                }
            }

            //aとbを比較する
            private int Compare(T a, T b)
            {
                var c = a.CompareTo(b);
                if (!this.Greater)
                {
                    c = -c;
                }
                return c;
            }

            //aとbを入れ替える
            private void Swap(int a, int b)
            {
                var tmp = this.Array[a];
                this.Array[a] = this.Array[b];
                this.Array[b] = tmp;
            }
        }

        private static bool NextPermutation(int[] array)
        {
            var size = array.Length;
            var ok = false;

            //array[i]<array[i+1]を満たす最大のiを求める
            int i = size - 2;
            for (; 0 <= i; i--)
            {
                if (array[i] < array[i + 1])
                {
                    ok = true;
                    break;
                }
            }

            //全ての要素が降順の場合、NextPermutationは存在しない
            if (ok == false) return false;

            //array[i]<array[j]を満たす最大のjを求める
            int j = size - 1;
            for (; ; j--)
            {
                if (array[i] < array[j]) break;
            }

            //iとjの要素をswapする
            var tmp = array[i];
            array[i] = array[j];
            array[j] = tmp;

            //i以降の要素を反転させる
            Array.Reverse(array, i + 1, size - (i + 1));

            return true;
        }

        //要素数Nを引数として渡し、0～N-1でできた順列をすべて返す
        static List<int[]> GetAllPermutation(int N)
        {
            var res = new List<int[]>();
            var array = Enumerable.Range(0, N).ToArray();
            do
            {
                var copy = new int[N];
                array.CopyTo(copy, 0);
                res.Add(copy);
            } while (NextPermutation(array));

            return res;
        }

        //配列arrayを引数として渡し,辞書順がarray以上の順列をすべて返す
        static List<int[]> GetAllPermutation(int[] array)
        {
            var size = array.Length;
            var res = new List<int[]>();
            do
            {
                var copy = new int[size];
                array.CopyTo(copy, 0);
                res.Add(copy);
            } while (NextPermutation(array));

            return res;
        }
    }
}


public static class Extentions
{
    public static int Int(this object obj)
    {
        return int.Parse(obj.ToString());
    }

    public static long Long(this object obj)
    {
        return long.Parse(obj.ToString());
    }

    public static decimal Decimal(this object obj)
    {
        return decimal.Parse(obj.ToString());
    }

    public static double Double(this object obj)
    {
        return double.Parse(obj.ToString());
    }

    public static T2 GetValueZero<T1, T2>(this Dictionary<T1, T2> d, T1 key) where T2 : struct
    {
        T2 value;
        if (d.TryGetValue(key, out value))
        {
            return value;
        }
        return new T2();
    }
}