Problem:
Score : 400 points

Problem Statement

There is a grid with H horizontal rows and W vertical columns, and there are obstacles on some of the squares.

Snuke is going to choose one of the squares not occupied by an obstacle and place a lamp on it.
The lamp placed on the square will emit straight beams of light in four cardinal directions: up, down, left, and right.
In each direction, the beam will continue traveling until it hits a square occupied by an obstacle or it hits the border of the grid. It will light all the squares on the way, including the square on which the lamp is placed, but not the square occupied by an obstacle.

Snuke wants to maximize the number of squares lighted by the lamp.

You are given H strings S_i (1 \leq i \leq H), each of length W. If the j-th character (1 \leq j \leq W) of S_i is #, there is an obstacle on the square at the i-th row from the top and the j-th column from the left; if that character is ., there is no obstacle on that square.

Find the maximum possible number of squares lighted by the lamp.

Constraints

1 \leq H \leq 2,000

1 \leq W \leq 2,000

S_i is a string of length W consisting of # and ..

. occurs at least once in one of the strings S_i (1 \leq i \leq H).

Input

Input is given from Standard Input in the following format:

H W
S_1
:
S_H

Output

Print the maximum possible number of squares lighted by the lamp.

Sample Input 1

4 6
#..#..
.....#
....#.
#.#...

Sample Output 1

8

If Snuke places the lamp on the square at the second row from the top and the second column from the left, it will light the following squares: the first through fifth squares from the left in the second row, and the first through fourth squares from the top in the second column, for a total of eight squares.

Sample Input 2

8 8
..#...#.
....#...
##......
..###..#
...#..#.
##....#.
#...#...
###.#..#

Sample Output 2

13

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

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;

namespace ABC129D
{
    class Program
    {
        static void Solve(Input input)
        {
            var h = input.NextInt();
            var w = input.NextInt();
            var map = new int[h, w];

            for (int i = 0; i < h; i++)
            {
                var s = input.Next();
                for (int j = 0; j < w; j++)
                {
                    // 障害物あり
                    if (s[j] == '#') map[i, j] = 1;
                }
            }

            // h,wがそんなに大きくないので、すべてのマスの照らされるマスを数え上げる
            // TLEするなら周辺のマスをいい感じに使う？
            var max = int.MinValue;
            // [x,y,xy]: xy=0はそのマスのx座標でのカウント値
            // xy=1はそのマスのy座標でのカウント値
            // ただし、自分のマスを重複カウントしているので実際の値は2つの和-1
            var countMap = new int[h, w, 2];
            for (int i = 0; i < h; i++)
            {
                for (int j = 0; j < w; j++)
                {
                    light(map, countMap, h, w, j, i);
                    var count = countMap[i, j, 0] + countMap[i, j, 1] - 1;
                    if (count > max) max = count;
                }
            }

            Console.WriteLine(Math.Max(0, max));
        }

        static void light(int[,] map, int[,,] cmap, int h, int w, int x, int y)
        {
            if (map[y, x] != 0)
            {
                cmap[y, x, 0] = cmap[y, x, 1] = 0;
                return;
            }

            if (x > 0 && cmap[y, x - 1, 0] != 0)
            {
                cmap[y, x, 0] = cmap[y, x - 1, 0];
            }
            else
            {
                int count = 0;

                // x+
                for (int j = x + 1; j < w; j++)
                {
                    if (map[y, j] != 0) break;
                    count++;
                }
                // x-
                for (int j = x - 1; j >= 0; j--)
                {
                    if (map[y, j] != 0) break;
                    count++;
                }

                cmap[y, x, 0] = count + 1;
            }
            if (y > 0 && cmap[y - 1, x, 1] != 0)
            {
                cmap[y, x, 1] = cmap[y - 1, x, 1];
            }
            else
            {
                int count = 0;

                // y+
                for (int i = y + 1; i < h; i++)
                {
                    if (map[i, x] != 0) break;
                    count++;
                }
                // y-
                for (int i = y - 1; i >= 0; i--)
                {
                    if (map[i, x] != 0) break;
                    count++;
                }

                cmap[y, x, 1] = count + 1;
            }
        }

        #region Competitive Template
        public static void Main(string[] args)
        {
            var needsFlushOutput = true;
            if (needsFlushOutput)
            {
                // 細かく出力しないようにする
                var sw = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false };
                Console.SetOut(sw);
            }

            // 通常は引数無しで、ファイルから読み出したい場合はpath指定する
            var input = new Input();
            // 仮想的に標準入力をセットする
            //input.SetText("");

            Solve(input);

            Console.Out.Flush();
        }

        class Input
        {
            // 変な改行コードがたまに混じっているので、一応セパレート指定する
            static readonly char[] separator = { ' ', '\r', '\n' };
            public bool IsEof { get; set; }
            Queue<string> q { get; set; }
            StreamReader sr;

            public Input(string path = "")
            {
                IsEof = false;
                q = new Queue<string>();

                if (string.IsNullOrEmpty(path))
                {
                    sr = new StreamReader(Console.OpenStandardInput());
                }
                else
                {
                    sr = new StreamReader(path);
                }
            }

            /// <summary>
            /// 入力予約
            /// </summary>
            /// <param name="items"></param>
            public void SetText(IEnumerable<string> items)
            {
                foreach (var item in items)
                {
                    SetText(item);
                }
            }

            /// <summary>
            /// 入力予約
            /// </summary>
            /// <param name="s"></param>
            /// <returns></returns>
            public bool SetText(string s)
            {
                if (s == null) return false;

                foreach (var elem in s.Trim().Split(separator, StringSplitOptions.RemoveEmptyEntries))
                {
                    q.Enqueue(elem);
                }

                return true;
            }

            /// <summary>
            /// 内部queueに入力からの値をsplitして格納する
            /// </summary>
            /// <returns></returns>
            bool read()
            {
                var s = sr.ReadLine();
                if (s == null) return false;

                foreach (var elem in s.Trim().Split(separator, StringSplitOptions.RemoveEmptyEntries))
                {
                    q.Enqueue(elem);
                }

                if (!q.Any()) return read();

                return true;
            }

            /// <summary>
            /// 次のstringを一つ読み込む
            /// </summary>
            /// <returns></returns>
            public string Next()
            {
                if (!q.Any())
                {
                    if (!read())
                    {
                        IsEof = true;
                        return "";
                    }
                }

                return q.Dequeue();
            }

            public int NextInt() => int.Parse(Next());
            public long NextLong() => long.Parse(Next());
            public double NextDouble() => double.Parse(Next());

            public string[] Next(int n) => Enumerable.Range(0, n).Select(_ => Next()).ToArray();
            public int[] NextInt(int n) => Next(n).Select(x => int.Parse(x)).ToArray();
            public long[] NextLong(int n) => Next(n).Select(x => long.Parse(x)).ToArray();
            public double[] NextDouble(int n) => Next(n).Select(x => double.Parse(x)).ToArray();
        }

        static class Utils
        {
            public static void Print<T>(IEnumerable<T> ie, string sep = " ") => Console.WriteLine(string.Join(sep, ie));
            public static void Print<T>(params T[] objs) => Print(objs);
            public static T Max<T>(params T[] objs) => objs.Max();
            public static T Min<T>(params T[] objs) => objs.Min();

            public static void Swap<T>(ref T x, ref T y) where T : struct { var t = x; x = y; y = t; }
            public static void Swap<T>(IList<T> list, int i, int j) where T : struct { var t = list[i]; list[i] = list[j]; list[j] = t; }

        }
        #endregion
    }
}