n,m = map(int, raw_input().split()) start = [raw_input() for __ in xrange(n)] finish = [raw_input() for __ in xrange(n)] count_row = [0 for __ in xrange(n)] count_col = [0 for __ in xrange(m)] for i in xrange(n): count_row[i] = sum(finish[i][j] == 'X' for j in xrange(m)) for j in xrange(m): count_col[j] = sum(finish[i][j] == 'X' for i in xrange(n)) forbidden_rows = set() forbidden_cols = set() # if there are two down pegs in a row or column, we can't ever perform move on the rows and cols of those pegs for i in xrange(n): for j in xrange(m): if finish[i][j] == 'X' and (count_row[i] >= 2 or count_col[j] >= 2): forbidden_rows.add(i) forbidden_cols.add(j) # for each nonforbidden row/col, it can only have at most one down peg that is in a nonforbidden col/row. haszero = False hasnonzero = False same = True for i in xrange(n): for j in xrange(m): if i not in forbidden_rows and j not in forbidden_cols: haszero = haszero or finish[i][j] == 'X' hasnonzero = hasnonzero or start[i][j] == 'O' same = same and start[i][j] == finish[i][j] # so far, we are ok if we are all the same, or there is some down peg in finish not in a forbidden row/col and some up peg in start ok = same or (haszero and hasnonzero) # now we look at things that lie in a forbidden row or column and check for differences for i in xrange(n): for j in xrange(m): if (i in forbidden_rows or j in forbidden_cols) and start[i][j] != finish[i][j]: if finish[i][j] == 0 or (i in forbidden_rows and j in forbidden_cols): # if this is hammered down, it is impossible since we can't fix it directly (might not need to check since this implies second condition will be true) # if this is in a forbidden row and column, there is no way to fix it indirectly ok = False else: # we might be able to use an allowed row or column to pop this peg back up # can only do this if there is up peg in start and down peg in finish ok = ok and (haszero and hasnonzero) print 1 if ok else 0