Problem:
Daruma Otoshi

You are playing a variant of a game called "Daruma Otoshi (Dharma Block Striking)".

At the start of a game, several wooden blocks of the same size but with varying weights
are stacked on top of each other, forming a tower.
Another block symbolizing Dharma is placed atop.
You have a wooden hammer with its head thicker than the height of a block,
but not twice that.

You can choose any two adjacent blocks, except Dharma on the top,
differing at most 1 in their weight,
and push both of them out of the stack with a single blow of your hammer.
The blocks above the removed ones then fall straight down,
without collapsing the tower.

You cannot hit a block pair with weight difference of 2 or more,
for that makes too hard to push out blocks while keeping the balance of the tower.
There is no chance in hitting three blocks out at a time,
for that would require superhuman accuracy.

The goal of the game is to remove as many blocks as you can.
Your task is to decide the number of blocks that can be removed
by repeating the blows in an optimal order.

Figure D1. Striking out two blocks at a time

In the above figure, with a stack of four blocks weighing 1, 2, 3, and
1, in this order from the bottom, you can hit middle
two blocks, weighing 2 and 3, out from the stack. The blocks above will
then fall down, and two blocks weighing 1 and the Dharma block will remain.
You can then push out the remaining pair of weight-1 blocks after that.

Input

The input consists of multiple datasets.
The number of datasets is at most 50.
Each dataset is in the following format.

n

w1 w2 … wn

n is the number of blocks, except Dharma on the top.
n is a positive integer not exceeding 300.
wi gives the weight of the i-th block counted from the bottom.
wi is an integer between 1 and 1000, inclusive.

The end of the input is indicated by a line containing a zero.

Output

For each dataset, output in a line the maximum number of blocks you can remove.

Sample Input

4
1 2 3 4
4
1 2 3 1
5
5 1 2 3 6
14
8 7 1 4 3 5 4 1 6 8 10 4 6 5
5
1 3 5 1 3
0

Output for the Sample Input

4
4
2
12
0

Solution in C# (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using static Library.Input;

namespace AtCoderTemplate {
    class ProgramF {
        static int[][] dp;
        static int[] weight;
        static int n;

        static void Main () {
            while (true)
            {
                n = NextInt;
                if (n == 0) return;
                weight = IntList.ToArray();
                dp = Enumerable.Range(0, n).Select(_ => Enumerable.Repeat(-1, n).ToArray()).ToArray();

                System.Console.WriteLine(Memo(0, n - 1));
            }
        }

        static int Memo(int left, int right) {
            if (dp[left][right] != -1) return dp[left][right];
            if (left == right) return dp[left][right] = 0;
            if (right - left == 1) return dp[left][right] = Math.Abs(weight[right] - weight[left]) <= 1 ? 2 : 0;

            // 中と外で区切る
            if (Math.Abs(weight[left] - weight[right]) <= 1 && Memo(left + 1, right - 1) == right - left - 1)
                return dp[left][right] = Memo(left + 1, right - 1) + 2;

            // 左と右で区切る
            return dp[left][right] = Enumerable.Range(left, right - left).Max(i => Memo(left, i) + Memo(i + 1, right));
        }
    }

}

namespace Library {
    class Input {
        static IEnumerator<string> enumerator = new string[] { }.AsEnumerable ().GetEnumerator ();

        public static string Line => Console.ReadLine ();

        public static string[] StrArr => Line.Split (' ');

        public static int NextInt => int.Parse (NextWord ());

        public static long NextLong => long.Parse (NextWord ());

        public static List<int> IntList => StrArr.Select (int.Parse).ToList ();

        public static List<long> LongList => StrArr.Select (long.Parse).ToList ();

        public static IEnumerable<long[]> TakeLine (int N) {
            return Enumerable.Repeat (0, N).Select (_ => Console.ReadLine ().Split (' ').Select (long.Parse).ToArray ());
        }

        public static string NextWord () {
            while (!enumerator.MoveNext ()) {
                enumerator = StrArr.AsEnumerable ().GetEnumerator ();
            }
            return enumerator.Current;
        }
    }
}