#include <bits/stdc++.h>
using namespace std;
long long int mod = 1000000007;
vector<int> tempArray;
class mySet {
  vector<int> elementPosition;
  int maxElement;

 public:
  vector<int> elementConatiner;
  mySet(int n) {
    maxElement = n;
    elementConatiner.clear();
    elementPosition.resize(n + 1);
    for (int i = 0; i <= n; i++) elementPosition[i] = -1;
  }
  void insert(int x) {
    if (elementPosition[x] == -1) {
      elementPosition[x] = (int)elementConatiner.size();
      elementConatiner.push_back(x);
    }
  }
  void deleteLazy(int x) {
    if (elementPosition[x] != -1) {
      elementConatiner[elementPosition[x]] = maxElement + 7;
      elementPosition[x] = -1;
    }
  }
  void deleteNow() {
    tempArray.clear();
    for (int i = 0; i < (int)elementConatiner.size(); i++)
      if (0 <= elementConatiner[i] && elementConatiner[i] <= maxElement)
        tempArray.push_back(elementConatiner[i]);
    elementConatiner.clear();
    for (int i = 0; i < (int)elementPosition.size(); i++)
      elementPosition[i] = -1;
    for (int i = 0; i < (int)tempArray.size(); i++) {
      elementPosition[tempArray[i]] = (int)elementConatiner.size();
      elementConatiner.push_back(tempArray[i]);
    }
    tempArray.clear();
  }
  void clear() {
    elementConatiner.clear();
    for (int i = 0; i <= maxElement; i++) elementPosition[i] = -1;
  }
  int count(int x) {
    if (x > maxElement || x < 0) return 0;
    if (elementPosition[x] == -1) return 0;
    return 1;
  }
  int popElement() {
    int x = elementConatiner[(int)elementConatiner.size() - 1];
    elementPosition[x] = -1;
    elementConatiner.pop_back();
    return x;
  }
};
bitset<(1 << 14) + 1> board[(1 << 12)];
char s[(1 << 12) + 1];
int tempRows[2][(1 << 14) + 1];
int parent[(1 << 15) + 1];
int height[(1 << 15) + 1];
mySet taken((1 << 14) + 1);
mySet available((1 << 14) + 1);
mySet camedown((1 << 14) + 1);
mySet haventcomedown((1 << 14) + 1);
int find(int x) {
  if (parent[x] != x) parent[x] = find(parent[x]);
  return parent[x];
}
void Union(int x, int y) {
  int px = find(x);
  int py = find(y);
  if (px == py) return;
  if (height[px] < height[py])
    parent[px] = py;
  else
    parent[py] = px;
  if (height[px] == height[py]) height[px]++;
}
int main() {
  int i, j, k, l, m, n, p, q, x, y, z, a, b, r, cur;
  scanf("%d", &n);
  scanf("%d", &m);
  for (i = 0; i < n; i++) {
    scanf("%s", s);
    for (j = 0; j < m / 4; j++) {
      switch (s[j]) {
        case 'A':
          x = 10;
          break;
        case 'B':
          x = 11;
          break;
        case 'C':
          x = 12;
          break;
        case 'D':
          x = 13;
          break;
        case 'E':
          x = 14;
          break;
        case 'F':
          x = 15;
          break;
        default:
          x = s[j] - '0';
          break;
      }
      for (k = 0; k < 4; k++) board[i].set(j * 4 + (3 - k), ((x >> k) & 1));
    }
  }
  int ans = 0;
  for (i = 1; i <= m; i++) available.insert(i);
  cur = 0;
  for (i = 0; i < n; i++) {
    for (j = 0; j < m; j++) tempRows[1 - cur][j] = 0;
    for (j = 0; j <= m; j++) parent[j] = j, height[j] = 0;
    if (i != 0) {
      camedown.clear();
      haventcomedown.clear();
      for (j = 0; j < m; j++) {
        if (board[i - 1].test(j) && board[i].test(j)) {
          tempRows[1 - cur][j] = tempRows[cur][j];
          camedown.insert(tempRows[cur][j]);
        }
      }
      for (j = 0; j < (int)taken.elementConatiner.size(); j++) {
        x = taken.elementConatiner[j];
        if (camedown.count(x) == 0) haventcomedown.insert(x);
      }
      for (j = 0; j < (int)haventcomedown.elementConatiner.size(); j++) {
        x = haventcomedown.elementConatiner[j];
        ans++;
        available.insert(x);
        taken.deleteLazy(x);
      }
    }
    taken.deleteNow();
    j = 0;
    while (j < m) {
      k = j;
      if (board[i].test(k)) {
        x = INT_MAX;
        if (tempRows[1 - cur][k] != 0) x = tempRows[1 - cur][k];
        while (k + 1 < m && board[i].test(k + 1)) {
          if (tempRows[1 - cur][k + 1] != 0) {
            if (x != INT_MAX)
              Union(x, tempRows[1 - cur][k + 1]);
            else
              x = tempRows[1 - cur][k + 1];
          }
          k++;
        }
      }
      j = k + 1;
    }
    j = 0;
    while (j < m) {
      k = j;
      if (board[i].test(k)) {
        x = INT_MAX;
        if (tempRows[1 - cur][k] != 0) x = find(tempRows[1 - cur][k]);
        while (k + 1 < m && board[i].test(k + 1)) {
          if (tempRows[1 - cur][k + 1] != 0) x = find(tempRows[1 - cur][k + 1]);
          k++;
        }
        if (x != INT_MAX)
          for (l = j; l <= k; l++) {
            if (tempRows[1 - cur][l] != x && tempRows[1 - cur][l] != 0) {
              taken.deleteLazy(tempRows[1 - cur][l]);
              available.insert(tempRows[1 - cur][l]);
            }
            tempRows[1 - cur][l] = x;
          }
      }
      j = k + 1;
    }
    taken.deleteNow();
    j = 0;
    while (j < m) {
      k = j;
      if (board[i].test(k) && tempRows[1 - cur][k] == 0) {
        x = available.popElement();
        taken.insert(x);
        while (k + 1 < m && board[i].test(k + 1)) k++;
        for (l = j; l <= k; l++) tempRows[1 - cur][l] = x;
      }
      j = k + 1;
    }
    cur = 1 - cur;
  }
  ans += (int)taken.elementConatiner.size();
  cout << ans << endl;
  return 0;
}
