// Arup Guha
// 11/27/2020
// Solution to 2019 NAIPC Problem: Busy Board

import java.util.*;
import java.io.*;

public class busyboard {
	
	public static int r;
	public static int c;
	public static boolean[][] start;
	public static boolean[][] end;
	
	public static void main(String[] args) throws Exception {
		
		BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer tok = new StringTokenizer(stdin.readLine());
		r = Integer.parseInt(tok.nextToken());
		c = Integer.parseInt(tok.nextToken());
		start = readBoard(stdin, r,c);
		end = readBoard(stdin, r, c);
		System.out.println(go());
	}
	
	public static int go() {
	
		// Get this case out of the way.
		if (equal()) return 1;
		
		// Can't get to anything else from this starting board.
		if (allMatch(start, false)) return 0;
		
		// Can't get to this board from anything else.
		if (allMatch(end, true)) return 0;
		
		// Mark all rows and columns that can't be hit.
		int[] downRowCnt = new int[r];
		for (int i=0; i<r; i++) downRowCnt[i] = downRowCount(i);
		int[] downColCnt = new int[c];
		for (int i=0; i<c; i++) downColCnt[i] = downColCount(i);
		
		// The different states we have to keep track of.
		boolean downToUp = false;
		boolean endDown = false;
		boolean startUp = false;
		
		// Now, analyze all squares.
		for (int i=0; i<r; i++) {
			for (int j=0; j<c; j++) {
		
				// These squares can't change because the only places that could change them
				// are forbidden.
				if (downRowCnt[i]>=2 && downColCnt[j]>=2 && start[i][j] != end[i][j])
					return 0;
					
				// If I am on a bad row, I can't change from up to down, since that means I would get hit.
				if (downRowCnt[i]>=2 && start[i][j] && !end[i][j])
					return 0;
					
				// Same logic for columns.
				if (downColCnt[j]>=2 && start[i][j] && !end[i][j])
					return 0;
				
				// At least one peg has to go from down to up...
				if (!start[i][j] && end[i][j])
					downToUp = true;		
				
				// We have something that ends down that could have been hit.
				if (downRowCnt[i]<2 && downColCnt[j]<2 && !end[i][j]) 
					endDown = true;
				
				// We have something that starts up, that could have been hit.
				if (downRowCnt[i]<2 && downColCnt[j]<2 && start[i][j])
					startUp = true;			
			}
		}
		
		// Can't propagate a change here.
		if (downToUp && !endDown) return 0;
		if (downToUp && !startUp) return 0;
		
		// Okay.
		return 1;
	}
	
	// Reads in a board with myr rows and myc columns and returns it.
	public static boolean[][] readBoard(BufferedReader stdin, int myr, int myc) throws Exception {
		boolean[][] res = new boolean[myr][myc];
		for (int i=0; i<myr; i++) {
			char[] line = stdin.readLine().trim().toCharArray();
			for (int j=0; j<myc; j++)
				res[i][j] = line[j] == 'O';
		}
		return res;
	}
	
	// Returns true iff the boards are equal.
	public static boolean equal() {
		for (int i=0; i<r; i++)
			for (int j=0; j<c; j++)
				if (start[i][j] != end[i][j])
					return false;
		return true;
	}
	
	// Returns true iff everything in board equals item.
	public static boolean allMatch(boolean[][] board, boolean item) {
		for (int i=0; i<r; i++)
			for (int j=0; j<c; j++)
				if (board[i][j] != item)
					return false;
		return true;
	}
	
	// A row can't be hit if it has two or more pegs down at the end.
	public static int downRowCount(int x) {
		int downCount = 0;
		for (int i=0; i<c; i++)
			if (!end[x][i])
				downCount++;
		return downCount;
	}
	
	// A column can't be hit if it has two or more pegs down at the end.
	public static int downColCount(int y) {
		int downCount = 0;
		for (int i=0; i<r; i++)
			if (!end[i][y])
				downCount++;
		return downCount;
	}	
	
}