Problem:
Score : 1400 points

Problem Statement

We have a grid with H rows and W columns.
The state of the cell at the i-th (1≤i≤H) row and j-th (1≤j≤W) column is represented by a letter a_{ij}, as follows:

. : This cell is empty.

o : This cell contains a robot.

E : This cell contains the exit. E occurs exactly once in the whole grid.

Snuke is trying to salvage as many robots as possible, by performing the following operation some number of times:

Select one of the following directions: up, down, left, right. All remaining robots will move one cell in the selected direction, except when a robot would step outside the grid, in which case the robot will explode and immediately disappear from the grid. If a robot moves to the cell that contains the exit, the robot will be salvaged and immediately removed from the grid.

Find the maximum number of robots that can be salvaged.

Constraints

2≤H,W≤100

a_{ij} is ., o or E.

E occurs exactly once in the whole grid.

Input

The input is given from Standard Input in the following format:

H W
a_{11}...a_{1W}
:
a_{H1}...a_{HW}

Output

Print the maximum number of robots that can be salvaged.

Sample Input 1

3 3
o.o
.Eo
ooo

Sample Output 1

3

For example, select left, up, right.

Sample Input 2

2 2
E.
..

Sample Output 2

0

Sample Input 3

3 4
o...
o...
oooE

Sample Output 3

5

Select right, right, right, down, down.

Sample Input 4

5 11
ooo.ooo.ooo
o.o.o...o..
ooo.oE..o..
o.o.o.o.o..
o.o.ooo.ooo

Sample Output 4

12

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

using System;
using System.Linq;
using System.Collections.Generic;
using Debug = System.Diagnostics.Debug;
using StringBuilder = System.Text.StringBuilder;
using System.Numerics;
using Point = System.Numerics.Complex;
using Number = System.Int64;
namespace Program
{
    public class Solver
    {

        public void Solve()
        {
            var h = sc.Integer();
            var w = sc.Integer();
            var a = Enumerate(h, x => new int[w]);
            var px = -1; var py = -1;
            for (int i = 0; i < h; i++)
                for (int j = 0; j < w; j++)
                {
                    var x = sc.Char();
                    if (x == 'o') a[i][j] = 1;
                    if (x == 'E') { px = i; py = j; }
                }
            var b = createCumulativeSum(a);
            //i<=j&&k<=l
            var dp = new short[h, h, w, w];
            for (int i = 0; i < h; i++)
                for (int j = i; j < h; j++)
                    for (int k = 0; k < w; k++)
                        for (int l = k; l < w; l++)
                            dp[i, j, k, l] = -20000;

            var max = 0;
            dp[0, h - 1, 0, w - 1] = 0;
            for (int i = 0; i < h; i++)
                for (int j = h - 1; j >= i; j--)
                    for (int k = 0; k < w; k++)
                        for (int l = w - 1; l >= k; l--)
                        {
                            if (dp[i, j, k, l] < 0) continue;
                            max = Math.Max(max, dp[i, j, k, l]);
                            var ue = Math.Max(i, px - ((h - 1) - j));
                            var sita = Math.Min(j, px + i);
                            var hidari = Math.Max(k, py - ((w - 1) - l));
                            var migi = Math.Min(l, py + k);

                            //ue kesu
                            if (i + 1 <= j && sita + 1 <= j)
                                dp[i + 1, j, k, l] = Math.Max(dp[i + 1, j, k, l], (short)(dp[i, j, k, l] + getArea(b, sita + 1, hidari, sita + 2, migi + 1)));
                            //sita kesu
                            if (i <= j - 1 && i <= ue - 1)
                                dp[i, j - 1, k, l] = Math.Max(dp[i, j - 1, k, l], (short)(dp[i, j, k, l] + getArea(b, ue - 1, hidari, ue, migi + 1)));
                            //hidari kesu
                            if (k + 1 <= l && migi + 1 <= l)
                                dp[i, j, k + 1, l] = Math.Max(dp[i, j, k + 1, l], (short)(dp[i, j, k, l] + getArea(b, ue, migi + 1, sita + 1, migi + 2)));
                            //migi kesu
                            if (k <= l - 1 && k <= hidari - 1)
                                dp[i, j, k, l - 1] = Math.Max(dp[i, j, k, l - 1], (short)(dp[i, j, k, l] + getArea(b, ue, hidari - 1, sita + 1, hidari)));

                        }
            IO.Printer.Out.WriteLine(max);

        }
        static public Func<int[][], int[][]> createCumulativeSum = s =>
        {
            int n = s.Length, m = s[0].Length;
            var a = new int[n + 1][];
            for (int i = 0; i <= n; i++)
                a[i] = new int[m + 1];
            for (int i = 0; i < n; i++)
                for (int j = 0; j < m; j++)
                    a[i + 1][j + 1] = a[i + 1][j] + a[i][j + 1] - a[i][j] + s[i][j];
            return a;
        };
        /// <summary>元のテーブルにおける[x1,x2),[y1,y2)の矩形領域に含まれる値の和を取ってくる</summary>
        static public Func<int[][], int, int, int, int, short> getArea = (a, x1, y1, x2, y2) =>
        {
            if (x1 >= x2 || y1 >= y2) return 0;
            return (short)(a[x2][y2] - a[x1][y2] - a[x2][y1] + a[x1][y1]);
        };


        public IO.StreamScanner sc = new IO.StreamScanner(Console.OpenStandardInput());
        static T[] Enumerate<T>(int n, Func<int, T> f) { var a = new T[n]; for (int i = 0; i < n; ++i) a[i] = f(i); return a; }
        static public void Swap<T>(ref T a, ref T b) { var tmp = a; a = b; b = tmp; }
    }
}

#region main
static class Ex
{
    static public string AsString(this IEnumerable<char> ie) { return new string(System.Linq.Enumerable.ToArray(ie)); }
    static public string AsJoinedString<T>(this IEnumerable<T> ie, string st = " ") { return string.Join(st, ie); }
    static public void Main()
    {
        var solver = new Program.Solver();
        solver.Solve();
        Program.IO.Printer.Out.Flush();
    }
}
#endregion
#region Ex
namespace Program.IO
{
    using System.IO;
    using System.Text;
    using System.Globalization;
    public class Printer: StreamWriter
    {
        static Printer() { Out = new Printer(Console.OpenStandardOutput()) { AutoFlush = false }; }
        public static Printer Out { get; set; }
        public override IFormatProvider FormatProvider { get { return CultureInfo.InvariantCulture; } }
        public Printer(System.IO.Stream stream) : base(stream, new UTF8Encoding(false, true)) { }
        public Printer(System.IO.Stream stream, Encoding encoding) : base(stream, encoding) { }
        public void Write<T>(string format, T[] source) { base.Write(format, source.OfType<object>().ToArray()); }
        public void WriteLine<T>(string format, T[] source) { base.WriteLine(format, source.OfType<object>().ToArray()); }
    }
    public class StreamScanner
    {
        public StreamScanner(Stream stream) { str = stream; }
        public readonly Stream str;
        private readonly byte[] buf = new byte[1024];
        private int len, ptr;
        public bool isEof = false;
        public bool IsEndOfStream { get { return isEof; } }
        private byte read()
        {
            if (isEof) return 0;
            if (ptr >= len) { ptr = 0; if ((len = str.Read(buf, 0, 1024)) <= 0) { isEof = true; return 0; } }
            return buf[ptr++];
        }
        public char Char() { byte b = 0; do b = read(); while ((b < 33 || 126 < b) && !isEof); return (char)b; }

        public string Scan()
        {
            var sb = new StringBuilder();
            for (var b = Char(); b >= 33 && b <= 126; b = (char)read())
                sb.Append(b);
            return sb.ToString();
        }
        public string ScanLine()
        {
            var sb = new StringBuilder();
            for (var b = Char(); b != '\n'; b = (char)read())
                if (b == 0) break;
                else if (b != '\r') sb.Append(b);
            return sb.ToString();
        }
        public long Long()
        {
            if (isEof) return long.MinValue;
            long ret = 0; byte b = 0; var ng = false;
            do b = read();
            while (b != 0 && b != '-' && (b < '0' || '9' < b));
            if (b == 0) return long.MinValue;
            if (b == '-') { ng = true; b = read(); }
            for (; true; b = read())
            {
                if (b < '0' || '9' < b)
                    return ng ? -ret : ret;
                else ret = ret * 10 + b - '0';
            }
        }
        public int Integer() { return (isEof) ? int.MinValue : (int)Long(); }
        public double Double() { var s = Scan(); return s != "" ? double.Parse(s, CultureInfo.InvariantCulture) : double.NaN; }
        private T[] enumerate<T>(int n, Func<T> f)
        {
            var a = new T[n];
            for (int i = 0; i < n; ++i) a[i] = f();
            return a;
        }

        public char[] Char(int n) { return enumerate(n, Char); }
        public string[] Scan(int n) { return enumerate(n, Scan); }
        public double[] Double(int n) { return enumerate(n, Double); }
        public int[] Integer(int n) { return enumerate(n, Integer); }
        public long[] Long(int n) { return enumerate(n, Long); }
    }
}
#endregion