Problem:
長方形探索

縦に H 行、横に W 列並べられた、合計 W × H のマス目があります。いくつかのマス目には印がついています。各マス目の印の状態を読み込み、印のついていないマス目だけからなる最大の長方形の面積を出力するプログラムを作成してください。

入力データは 1 行 W 文字から構成され、H 行が与えられます。たとえば以下のようなデータが与えられます。

..*....**.
..........
**....***.
....*.....
..*.......
...**.....
.*.*......
..........
..**......
.*..*.....

入力データの一行が、一行のマス目を表現します。入力データの文字列のうち、. (ピリオド) は印のついていないマス目、* (アスタリスク) は印のついているマス目を示しています。入力データの文字列には、ピリオド、アスタリスク、改行以外の文字は含まれません。

上記の例では、下図の 0 で示される長方形が最大となります。

..*....**.
..........
**....***.
....*00000
..*..00000
...**00000
.*.*.00000
.....00000
..**.00000
.*..*00000

よって、35 と出力すれば正解になります。なお、すべてのマス目に印がついている場合には、0 を出力してください。

Input

複数のデータセットが与えられます。各データセットはスペースで区切られた H と W からなる行から始まり、つづいて H × W の長方形が与えられます。H, W はともに 500　以下とします。

入力は２つの 0 を含む行で終わります。データセットの数は 20 を超えません。

Output

各データセットごとに、最大の長方形の面積を１行に出力してください。

Sample Input

10 10
...*....**
..........
**....**..
........*.
..*.......
**........
.*........
..........
....*..***
.*....*...
10 10
..*....*..
.*.*...*..
*****..*..
*...*..*..
*...*..*..
..........
****.*...*
..*..*...*
.*...*...*
****..***.
2 3
...
...
0 0

Output for the Sample Input

28
12
6

Solution in C# (judge verdict: Accepted)

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

namespace ConsoleApplication1
{
    struct Rectangle
    {
        internal int height, pos;
    }

    class Program
    {
        static void Main(string[] args)
        {
            StringBuilder sb = new StringBuilder();

            while (true)
            {

                int[] input = Array.ConvertAll(Console.ReadLine().Split(' '), int.Parse);

                if (input.All(a => a == 0)) break;

                int H = input[0];
                int W = input[1];

                int[,] dp = new int[H, W + 1];

                for (int i = 0; i < H; i++)
                {
                    string line = Console.ReadLine();

                    for (int j = 0; j < W; j++)
                    {
                        if (line[j] == '*') dp[i, j] = 0;
                        else dp[i, j] = i > 0 ? dp[i - 1, j] + 1 : 1;
                    }
                }

                Stack<Rectangle> stk = new Stack<Rectangle>();
                int maxArea = 0;

                for (int i = 0; i < H; i++)
                {
                    for (int j = 0; j <= W; j++)
                    {
                        Rectangle rect;
                        rect.height = dp[i, j];
                        rect.pos = j;

                        if (stk.Count == 0)
                        {
                            stk.Push(rect);
                        }
                        else
                        {
                            if (stk.Peek().height < rect.height)
                            {
                                stk.Push(rect);
                            }
                            else if (stk.Peek().height > rect.height)
                            {
                                int target = j;

                                while (stk.Count > 0 && stk.Peek().height >= rect.height)
                                {
                                    Rectangle pre = stk.Pop();
                                    int area = pre.height * (j - pre.pos);
                                    maxArea = Math.Max(maxArea, area);
                                    target = pre.pos;
                                }
                                rect.pos = target;
                                stk.Push(rect);
                            }
                        }
                    }
                }
                sb.AppendLine(maxArea.ToString());
            }
            Console.Write(sb);
        }
    }
}