1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
#include <set>
#include <chrono>
#include <functional>
#include <cstdlib>
#include <cassert>
using namespace std;

struct Field
{
  bool isEmpty;
};

struct Table
{
  std::vector<std::vector<Field>> fields;
};

Table readTable(int n, int m)
{
  Table result;
  result.fields.resize(m);
  for (int i=0; i<m; ++i)
    result.fields[i].resize(n);
  for (int i = 0; i < n; ++i)
  {
    std::string word;
    std::cin >> word;
    for (int j=0; j<m; ++j)
      result.fields[j][n-1-i].isEmpty = word[j] =='.';
  }
  return result;
}

int getParity(Table& table)
{
  int numberOnBlack = 0;
  for (int i = 0; i < table.fields.size(); ++i)
  {
    for (int j = 0; j < table.fields[0].size(); ++j)
    {
      if (!table.fields[i][j].isEmpty && (i+j) % 2 == 0)
        numberOnBlack++;
    }
  }
  return numberOnBlack % 2;
}

int getPawnsNumber(Table& table)
{
  int pawnNumber = 0;
  for (int i = 0; i < table.fields.size(); ++i)
  {
    for (int j = 0; j < table.fields[0].size(); ++j)
    {
      if (!table.fields[i][j].isEmpty)
        pawnNumber++;
    }
  }
  return pawnNumber;
}

int getNumberOfMoves(Table& table)
{
  int numberOfMoves = 0;
  for (int x = 0; x < table.fields.size(); ++x)
  {
    for (int y = 0; y < table.fields[0].size() - 1; ++y)
    {
      if (table.fields[x][y].isEmpty != table.fields[x][y+1].isEmpty)
        numberOfMoves++;
    }
  }
  for (int y = 0; y < table.fields[0].size(); ++y)
  {
    for (int x = 0; x < table.fields.size() - 1; ++x)
    {
      if (table.fields[x][y].isEmpty != table.fields[x+1][y].isEmpty)
        numberOfMoves++;
    }
  }
  return numberOfMoves;
}

int main()
{
  const clock_t begin_time = clock();
  int n;
  int m;
  std::cin >> n >> m;

  Table startTable = readTable(n, m);

  Table endTable = readTable(n, m);

  if (getParity(startTable) != getParity(endTable))
  {
    std::cout << "0\n";
    return 0;
  }

  int numberOfMoves = getNumberOfMoves(endTable);
  int pawnNumber = getPawnsNumber(endTable);
  unsigned long long allPositions = 1;
  for (int i = 1; i <= pawnNumber - 1; ++i)
  {
    allPositions *= (n*m -1) -i;
    allPositions /=i;
  }
  unsigned long long numberNeibours = (m *(n-1)) + ((m-1)*n);
  double probability = 2 * (double)numberOfMoves / ((double)numberNeibours * allPositions * 2);
  std::cout.precision(15);
  std::cout << std::fixed << probability << "\n";


  return 0;
};