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 JAVA (judge verdict: Accepted)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;


public class Main {
	private	static	BufferedReader	br = null;

	static {
		br = new BufferedReader(new InputStreamReader(System.in));
	}
 
    /**
     * @param args
     */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[][] map = null;

		while((map = parseMap()) != null) {
			System.out.println(calcMaxSum(map));
		}
	}

	private static int calcMaxSum(int[][] map) {
		int	max = 0;

		for (int i = 0; i < map.length; i++) {
			for (int j = 0; j < map[i].length; j++) {
				int	l = map[i][j];
				if (l * (map.length-i) > max) {
					for (int k = 0; i+k < map.length; k++) {
						l = Math.min(l, map[i+k][j]);
						if (l * (map.length-i) <= max) {
							// 理論上、これ以上最大値を更新できない場合は計算しない
							break;
						} else {
							max = Math.max(max, l * (k+1));
						}
					}
				}
			}
		}

        return max;
	}

	private static int[][] parseMap() {
		int[][]	map = null;
		int[]	len = parseLen();

        if (len != null) {
			map = new int[len[0]][len[1]];

			for (int y = 0; y < len[0]; y++) {
				String	strin = null;
		        if ((strin = parseStdin()) != null) {
		        	for (int x = len[1]-1; x >= 0; x--) {
		        		if (strin.charAt(x) == (char)'.') {
		        			map[y][x] = (x < len[1]-1) ? ((map[y][x+1] != 0) ? map[y][x+1]+1 : 1) : 1;
		        		}
		        	}
		        }
			}
        }
 
        return map;
	}

	private static int[] parseLen() {
		int[]	params = null;
        String	stdin  = null;

        if ((stdin = parseStdin()) != null) {
			if (!stdin.equals("0 0")) {
				String[]	lines = stdin.split(" ");

				params    = new int[2]; 
				params[0] = Integer.parseInt(lines[0]);
				params[1] = Integer.parseInt(lines[1]);
			}
        }
 
        return params;
	}

	private static String parseStdin() {
        String  stdin = null;
        
        try {
        	String  tmp = br.readLine();
        	if (!tmp.isEmpty()) stdin = tmp;
        }
        catch (IOException e) {}
 
        return stdin;
	}
}