// Arup Guha
// 2/5/2023
// Solution to 2022 NAQ Problem E: MazeMan

import java.util.*;

public class mazeman {
	
	final public static int[] DX = {-1,0,0,1};
	final public static int[] DY = {0,-1,1,0};
	
	public static int r;
	public static int c;
	public static char[][] g;
	
	public static void main(String[] args) {
	
		Scanner stdin = new Scanner(System.in);
		StringTokenizer tok = new StringTokenizer(stdin.nextLine());
		r = Integer.parseInt(tok.nextToken());
		c = Integer.parseInt(tok.nextToken());
		g = new char[r][];
		for (int i=0; i<r; i++)
			g[i] = stdin.nextLine().toCharArray();
			
		// Mark X's as used.
		int res = 0;
		boolean[][] used = new boolean[r][c];
		for (int i=0; i<r*c; i++)
			if (g[i/c][i%c] == 'X')
				used[i/c][i%c] = true;
			
		// Just start from locations.
		for (int i=0; i<r; i++) {
			for (int j=0; j<c; j++) {
				
				// Can only start from an edge with a valid letter.
				if (i != 0 && j != 0 && i != r-1 && j != c-1) continue;
				if ((i==0 || i==r-1) && (j==0 || j==c-1)) continue;
				if (used[i][j]) continue;
				
				// Run the BFS from the adjacent location.
				res += bfs(getAdj(i,j),used); 
			}
		}
		
		// Count the unreached dots.
		int cant = 0;
		for (int i=1; i<r-1; i++)
			for (int j=1; j<c-1; j++)
				if (g[i][j] == '.' && !used[i][j]) cant++;
			
		// Ta da!
		System.out.println(res+" "+cant);
	}
	
	// Returns the code for the adjacent spot to (x,y) in the grid, given x,y is on an edge.
	public static int getAdj(int x, int y) {
		if (x == 0) return (c+y);
		if (x == r-1) return c*(x-1)+y;
		if (y == 0) return c*x + 1;
		return c*x + c - 2;
	}
	
	// Runs the BFS from loc. Returns 1 if at least 1 dot is eaten, 0 otherwise.
	public static int bfs(int loc, boolean[][] used) {
		
		// Convert...
		int sX = loc/c;
		int sY = loc%c;
		
		// Don't do BFS.
		if (used[sX][sY]) return 0;
		
		// Set up BFS, noting if we start ona  dot.
		LinkedList<Integer> q = new LinkedList<Integer>();
		q.offer(loc);
		used[sX][sY] = true;
		boolean flag = false;
		if (g[sX][sY] == '.') flag = true;
		
		// Run BFS.
		while (q.size() > 0) {
			
			// Get next.
			int cur = q.pollFirst();
			int cX = cur/c;
			int cY = cur%c;
			
			// Look adjacent.
			for (int i=0; i<4; i++) {
				
				// This is the adjacent location we're looking at.
				int mX = cX+DX[i];
				int mY = cY+DY[i];
				
				// All the reasons to skip it.
				if (!inbounds(mX, mY)) continue;
				if (used[mX][mY]) continue;
				
				// Process a dot.
				if (g[mX][mY] == '.') {
					flag = true;
					q.offer(mX*c+mY);
					used[mX][mY] = true;
				}
				
				// And a space.
				else {
					q.offer(mX*c+mY);
					used[mX][mY] = true;
				}				
			}
		}
		
		// Return appropriately.
		if (flag) return 1;
		return 0;
	}
	
	public static boolean inbounds(int x, int y) {
		return x>0 && x<r-1 && y>0 && y<c-1;
	}
}