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.util.*;
import java.io.*;

class Main {

    public static void main(String[] args) {

	final Scanner stdin = new Scanner(System.in);

	while ( true ) {
	    final String[] input = stdin.nextLine().split( " " );
	    final int height = Integer.parseInt( input[0] );
	    final int width = Integer.parseInt( input[1] );
	    
	    if ( height == 0 && width == 0 ) {
		break;
	    }

	    final char[][] map = new char[height][];
	    
	    for ( int i = 0; i < height; i++ ) {
		map[i] = stdin.nextLine().toCharArray(); 
	    }

	    final int[][] acCol = new int[height][width];
	    for ( int r = 0; r < width; r++ ) {
		acCol[0][r] = ( map[0][r] == '.' ) ? 1 : 0;
		for ( int c = 1; c < height; c++ ) {
		    if ( map[c][r] == '.' ) {
			acCol[c][r] = acCol[c - 1][r] + 1;
		    } else {
			acCol[c][r] = 0;	
		    }
		}
	    }

	    final int[][] acRow = new int[height][width];
	    for ( int c = 0; c < height; c++ ) {
		acRow[c][0] = ( map[c][0] == '.' ) ? 1 : 0;
		for ( int r = 1; r < width; r++ ) {
		    if ( map[c][r] == '.' ) {
			acRow[c][r] = acRow[c][r - 1] + 1;
		    } else {
			acRow[c][r] = 0;	
		    }
		}
	    }

	    int maxArea = 0;
	    
	    for ( int c = 0; c < height; c++ ) {
		for ( int r = 0; r < width; r++ ) {

		    int minHeight = Integer.MAX_VALUE;
		    for ( int ri = 0; ri < acRow[c][r]; ri++) {
			final int cr = r - ri;
			minHeight = Math.min( minHeight, acCol[c][cr] );
			final int area = ( r - cr + 1 ) * minHeight;
			maxArea = Math.max( maxArea, area );
		    }
		    
		}
	    }

	    System.out.println( maxArea );
	}
    }

    static void printArray( int[][] array ) {
	for ( int[] ar : array ) {
	    System.err.println( Arrays.toString( ar ) );
	}	
    }

    static void printArray( char[][] array ) {
	for ( char[] ar : array ) {
	    System.err.println( Arrays.toString( ar ) );
	}	
    }
    
}