//package educational.round31;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.InputMismatchException;

// 0516
public class E {
	InputStream is;
	PrintWriter out;
	String INPUT = "";

	void solve()
	{
		int n = ni(), m = ni();
		int[] clus = new int[m];
		Arrays.fill(clus, -1);
		int[] row = new int[m];
		long ans = 0;
		int[] loc = new int[2*m];
		for(int i = 0;i < n;i++){
			char[] line = ns(m/4);
			for(int j = 0;j < m;j++){
				int v = line[j/4] <= '9' ? line[j/4]-'0' : line[j/4]-'A'+10;
				row[j] = v<<~(3-(j&3))<0 ? j : -1;
				if(row[j] >= 0)ans++;
			}
			DJSet ds = new DJSet(2*m);
			for(int j = 0;j < m;j++){
				if(row[j] >= 0 && clus[j] >= 0){
					if(!ds.union(row[j], clus[j])){
						ans--;
					}
				}
				if(j > 0 && row[j-1] >= 0 && row[j] >= 0){
					if(!ds.union(row[j-1], row[j])){
						ans--;
					}
				}
			}
			int p = 0;
			for(int j = 0;j < 2*m;j++){
				if(ds.upper[j] < 0){
					loc[j] = p++;
				}
			}
			for(int j = 0;j < m;j++){
				clus[j] = row[j] == -1 ? -1 : loc[ds.root(row[j])] + m;
			}
		}
		out.println(ans);
	}

	public static class DJSet {
		public int[] upper;

		public DJSet(int n) {
			upper = new int[n];
			Arrays.fill(upper, -1);
		}

		public int root(int x) {
			return upper[x] < 0 ? x : (upper[x] = root(upper[x]));
		}

		public boolean equiv(int x, int y) {
			return root(x) == root(y);
		}

		public boolean union(int x, int y) {
			x = root(x);
			y = root(y);
			if (x != y) {
				if (upper[y] < upper[x]) {
					int d = x;
					x = y;
					y = d;
				}
				upper[x] += upper[y];
				upper[y] = x;
			}
			return x == y;
		}

		public int count() {
			int ct = 0;
			for (int u : upper)
				if (u < 0)
					ct++;
			return ct;
		}
	}

	void run() throws Exception
	{
		is = oj ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		out = new PrintWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		tr(System.currentTimeMillis()-s+"ms");
	}

	public static void main(String[] args) throws Exception { new E().run(); }

	private byte[] inbuf = new byte[1024];
	public int lenbuf = 0, ptrbuf = 0;

	private int readByte()
	{
		if(lenbuf == -1)throw new InputMismatchException();
		if(ptrbuf >= lenbuf){
			ptrbuf = 0;
			try { lenbuf = is.read(inbuf); } catch (IOException e) { throw new InputMismatchException(); }
			if(lenbuf <= 0)return -1;
		}
		return inbuf[ptrbuf++];
	}

	private boolean isSpaceChar(int c) { return !(c >= 33 && c <= 126); }
	private int skip() { int b; while((b = readByte()) != -1 && isSpaceChar(b)); return b; }

	private double nd() { return Double.parseDouble(ns()); }
	private char nc() { return (char)skip(); }

	private String ns()
	{
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ')
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	private char[] ns(int n)
	{
		char[] buf = new char[n];
		int b = skip(), p = 0;
		while(p < n && !(isSpaceChar(b))){
			buf[p++] = (char)b;
			b = readByte();
		}
		return n == p ? buf : Arrays.copyOf(buf, p);
	}

	private char[][] nm(int n, int m)
	{
		char[][] map = new char[n][];
		for(int i = 0;i < n;i++)map[i] = ns(m);
		return map;
	}

	private int[] na(int n)
	{
		int[] a = new int[n];
		for(int i = 0;i < n;i++)a[i] = ni();
		return a;
	}

	private int ni()
	{
		int num = 0, b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private long nl()
	{
		long num = 0;
		int b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private boolean oj = System.getProperty("ONLINE_JUDGE") != null;
	private void tr(Object... o) { if(!oj)System.out.println(Arrays.deepToString(o)); }
}


//package educational.round31;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.InputMismatchException;

// 0516
public class E {
	InputStream is;
	PrintWriter out;
	String INPUT = "";

	void solve()
	{
		int n = ni(), m = ni();
		int[] clus = new int[m];
		Arrays.fill(clus, -1);
		int[] row = new int[m];
		long ans = 0;
		for(int i = 0;i < n;i++){
			char[] line = ns(m/4);
			for(int j = 0;j < m;j++){
				int v = line[j/4] <= '9' ? line[j/4]-'0' : line[j/4]-'A'+10;
				row[j] = v<<~(j&3)<0 ? j : -1;
				if(row[j] >= 0)ans++;
			}
			DJSet ds = new DJSet(2*m);
			for(int j = 0;j < m;j++){
				if(row[j] >= 0 && clus[j] >= 0){
					if(!ds.union(row[j], clus[j])){
						ans--;
					}
				}
				if(j > 0 && row[j-1] >= 0 && row[j] >= 0){
					if(!ds.union(row[j-1], row[j])){
						ans--;
					}
				}
			}
			for(int j = 0;j < m;j++){
				clus[j] = row[j] == -1 ? -1 : ds.root(row[j]) + m;
			}
		}
		out.println(ans);
	}

	public static class DJSet {
		public int[] upper;

		public DJSet(int n) {
			upper = new int[n];
			Arrays.fill(upper, -1);
		}

		public int root(int x) {
			return upper[x] < 0 ? x : (upper[x] = root(upper[x]));
		}

		public boolean equiv(int x, int y) {
			return root(x) == root(y);
		}

		public boolean union(int x, int y) {
			x = root(x);
			y = root(y);
			if (x != y) {
				if (upper[y] < upper[x]) {
					int d = x;
					x = y;
					y = d;
				}
				upper[x] += upper[y];
				upper[y] = x;
			}
			return x == y;
		}

		public int count() {
			int ct = 0;
			for (int u : upper)
				if (u < 0)
					ct++;
			return ct;
		}
	}

	void run() throws Exception
	{
		is = oj ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		out = new PrintWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		tr(System.currentTimeMillis()-s+"ms");
	}

	public static void main(String[] args) throws Exception { new E().run(); }

	private byte[] inbuf = new byte[1024];
	public int lenbuf = 0, ptrbuf = 0;

	private int readByte()
	{
		if(lenbuf == -1)throw new InputMismatchException();
		if(ptrbuf >= lenbuf){
			ptrbuf = 0;
			try { lenbuf = is.read(inbuf); } catch (IOException e) { throw new InputMismatchException(); }
			if(lenbuf <= 0)return -1;
		}
		return inbuf[ptrbuf++];
	}

	private boolean isSpaceChar(int c) { return !(c >= 33 && c <= 126); }
	private int skip() { int b; while((b = readByte()) != -1 && isSpaceChar(b)); return b; }

	private double nd() { return Double.parseDouble(ns()); }
	private char nc() { return (char)skip(); }

	private String ns()
	{
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ')
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	private char[] ns(int n)
	{
		char[] buf = new char[n];
		int b = skip(), p = 0;
		while(p < n && !(isSpaceChar(b))){
			buf[p++] = (char)b;
			b = readByte();
		}
		return n == p ? buf : Arrays.copyOf(buf, p);
	}

	private char[][] nm(int n, int m)
	{
		char[][] map = new char[n][];
		for(int i = 0;i < n;i++)map[i] = ns(m);
		return map;
	}

	private int[] na(int n)
	{
		int[] a = new int[n];
		for(int i = 0;i < n;i++)a[i] = ni();
		return a;
	}

	private int ni()
	{
		int num = 0, b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private long nl()
	{
		long num = 0;
		int b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private boolean oj = System.getProperty("ONLINE_JUDGE") != null;
	private void tr(Object... o) { if(!oj)System.out.println(Arrays.deepToString(o)); }
}


//package educational.round31;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.InputMismatchException;

// 0516
public class E {
	InputStream is;
	PrintWriter out;
	String INPUT = "";

	void solve()
	{
		int n = ni(), m = ni();
		int[] clus = new int[m];
		Arrays.fill(clus, -1);
		int[] row = new int[m];
		long ans = 0;
		int[] loc = new int[3*m];
		for(int i = 0;i < n;i++){
			char[] line = ns(m/4);
			for(int j = 0;j < m;j++){
				int v = line[j/4] <= '9' ? line[j/4]-'0' : line[j/4]-'A'+10;
				row[j] = v<<~(j&3)<0 ? j : -1;
				if(row[j] >= 0)ans++;
			}
			DJSet ds = new DJSet(3*m);
			for(int j = 0;j < m;j++){
				if(row[j] >= 0 && clus[j] >= 0){
					if(!ds.union(row[j], clus[j])){
						ans--;
					}
				}
				if(j > 0 && row[j-1] >= 0 && row[j] >= 0){
					if(!ds.union(row[j-1], row[j])){
						ans--;
					}
				}
			}
			int p = 0;
			for(int j = 0;j < 3*m;j++){
				if(ds.upper[j] < 0){
					loc[j] = p++;
				}
			}
			for(int j = 0;j < m;j++){
				clus[j] = row[j] == -1 ? -1 : loc[ds.root(row[j])] + m;
			}
		}
		out.println(ans);
	}

	public static class DJSet {
		public int[] upper;

		public DJSet(int n) {
			upper = new int[n];
			Arrays.fill(upper, -1);
		}

		public int root(int x) {
			return upper[x] < 0 ? x : (upper[x] = root(upper[x]));
		}

		public boolean equiv(int x, int y) {
			return root(x) == root(y);
		}

		public boolean union(int x, int y) {
			x = root(x);
			y = root(y);
			if (x != y) {
				if (upper[y] < upper[x]) {
					int d = x;
					x = y;
					y = d;
				}
				upper[x] += upper[y];
				upper[y] = x;
			}
			return x == y;
		}

		public int count() {
			int ct = 0;
			for (int u : upper)
				if (u < 0)
					ct++;
			return ct;
		}
	}

	void run() throws Exception
	{
		is = oj ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		out = new PrintWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		tr(System.currentTimeMillis()-s+"ms");
	}

	public static void main(String[] args) throws Exception { new E().run(); }

	private byte[] inbuf = new byte[1024];
	public int lenbuf = 0, ptrbuf = 0;

	private int readByte()
	{
		if(lenbuf == -1)throw new InputMismatchException();
		if(ptrbuf >= lenbuf){
			ptrbuf = 0;
			try { lenbuf = is.read(inbuf); } catch (IOException e) { throw new InputMismatchException(); }
			if(lenbuf <= 0)return -1;
		}
		return inbuf[ptrbuf++];
	}

	private boolean isSpaceChar(int c) { return !(c >= 33 && c <= 126); }
	private int skip() { int b; while((b = readByte()) != -1 && isSpaceChar(b)); return b; }

	private double nd() { return Double.parseDouble(ns()); }
	private char nc() { return (char)skip(); }

	private String ns()
	{
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ')
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	private char[] ns(int n)
	{
		char[] buf = new char[n];
		int b = skip(), p = 0;
		while(p < n && !(isSpaceChar(b))){
			buf[p++] = (char)b;
			b = readByte();
		}
		return n == p ? buf : Arrays.copyOf(buf, p);
	}

	private char[][] nm(int n, int m)
	{
		char[][] map = new char[n][];
		for(int i = 0;i < n;i++)map[i] = ns(m);
		return map;
	}

	private int[] na(int n)
	{
		int[] a = new int[n];
		for(int i = 0;i < n;i++)a[i] = ni();
		return a;
	}

	private int ni()
	{
		int num = 0, b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private long nl()
	{
		long num = 0;
		int b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private boolean oj = System.getProperty("ONLINE_JUDGE") != null;
	private void tr(Object... o) { if(!oj)System.out.println(Arrays.deepToString(o)); }
}


//package educational.round31;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.InputMismatchException;

// 0516
public class E {
	InputStream is;
	PrintWriter out;
	String INPUT = "";

	void solve()
	{
		int n = ni(), m = ni();
		int[] clus = new int[m];
		Arrays.fill(clus, -1);
		int[] row = new int[m];
		long ans = 0;
		int[] loc = new int[2*m];
		DJSet ds = new DJSet(2*m);
		for(int i = 0;i < n;i++){
			char[] line = ns(m/4);
			for(int j = 0;j < m;j++){
				int v = line[j/4] <= '9' ? line[j/4]-'0' : line[j/4]-'A'+10;
				row[j] = v<<~(3-(j&3))<0 ? j : -1;
				if(row[j] >= 0)ans++;
			}
			for(int j = 0;j < m;j++){
				if(row[j] >= 0 && clus[j] >= 0){
					if(!ds.union(row[j], clus[j])){
						ans--;
					}
				}
				if(j > 0 && row[j-1] >= 0 && row[j] >= 0){
					if(!ds.union(row[j-1], row[j])){
						ans--;
					}
				}
			}
			int p = 0;
			for(int j = 0;j < 2*m;j++){
				if(ds.upper[j] < 0){
					loc[j] = p++;
				}
			}
			for(int j = 0;j < m;j++){
				clus[j] = row[j] == -1 ? -1 : loc[ds.root(row[j])] + m;
			}
		}
		out.println(ans);
	}

	public static class DJSet {
		public int[] upper;

		public DJSet(int n) {
			upper = new int[n];
			Arrays.fill(upper, -1);
		}

		public void clear()
		{
			Arrays.fill(upper, -1);
		}

		public int root(int x) {
			return upper[x] < 0 ? x : (upper[x] = root(upper[x]));
		}

		public boolean equiv(int x, int y) {
			return root(x) == root(y);
		}

		public boolean union(int x, int y) {
			x = root(x);
			y = root(y);
			if (x != y) {
				if (upper[y] < upper[x]) {
					int d = x;
					x = y;
					y = d;
				}
				upper[x] += upper[y];
				upper[y] = x;
			}
			return x == y;
		}

		public int count() {
			int ct = 0;
			for (int u : upper)
				if (u < 0)
					ct++;
			return ct;
		}
	}

	void run() throws Exception
	{
		is = oj ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		out = new PrintWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		tr(System.currentTimeMillis()-s+"ms");
	}

	public static void main(String[] args) throws Exception { new E().run(); }

	private byte[] inbuf = new byte[1024];
	public int lenbuf = 0, ptrbuf = 0;

	private int readByte()
	{
		if(lenbuf == -1)throw new InputMismatchException();
		if(ptrbuf >= lenbuf){
			ptrbuf = 0;
			try { lenbuf = is.read(inbuf); } catch (IOException e) { throw new InputMismatchException(); }
			if(lenbuf <= 0)return -1;
		}
		return inbuf[ptrbuf++];
	}

	private boolean isSpaceChar(int c) { return !(c >= 33 && c <= 126); }
	private int skip() { int b; while((b = readByte()) != -1 && isSpaceChar(b)); return b; }

	private double nd() { return Double.parseDouble(ns()); }
	private char nc() { return (char)skip(); }

	private String ns()
	{
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ')
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	private char[] ns(int n)
	{
		char[] buf = new char[n];
		int b = skip(), p = 0;
		while(p < n && !(isSpaceChar(b))){
			buf[p++] = (char)b;
			b = readByte();
		}
		return n == p ? buf : Arrays.copyOf(buf, p);
	}

	private char[][] nm(int n, int m)
	{
		char[][] map = new char[n][];
		for(int i = 0;i < n;i++)map[i] = ns(m);
		return map;
	}

	private int[] na(int n)
	{
		int[] a = new int[n];
		for(int i = 0;i < n;i++)a[i] = ni();
		return a;
	}

	private int ni()
	{
		int num = 0, b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private long nl()
	{
		long num = 0;
		int b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private boolean oj = System.getProperty("ONLINE_JUDGE") != null;
	private void tr(Object... o) { if(!oj)System.out.println(Arrays.deepToString(o)); }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.BufferedWriter;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author Fedor Poschmann (fedor.poschmann@gmail.com)
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        TaskE solver = new TaskE();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskE {
        public void solve(int testNumber, InputReader in, OutputWriter out) {
            long res = 0;
            int rows = in.readInt();
            int colums = in.readInt();

            int[] sliceDSU = new int[colums * 2];
            Arrays.fill(sliceDSU, -1);
            int numMerge = 0;
            int numBits = 0;

            for (int i = 0; i < rows; i++) {
                for (int j = 0; j < colums / 4; j++) {
                    int mask4bit = getChValue(in.readCharacter());
                    for (int k = 3; k >= 0; k--) {
                        int curX = j * 4 + 3 - k;
                        boolean flag = ((mask4bit >> k) & 1) == 1;
//                    System.out.print(flag?'1':'0');
                        if (flag) {
                            numBits++;
                            sliceDSU[curX + colums] = curX + colums;
                            // check left
                            if (curX > 0 && sliceDSU[curX - 1 + colums] != -1) {
                                // merge
                                int topId = findTop(sliceDSU, curX - 1 + colums);
                                numMerge++;
                                sliceDSU[topId] = curX + colums;
                            }
                            // check top
                            if (sliceDSU[curX] != -1) {
                                int topId = findTop(sliceDSU, curX);
                                int curTopId = findTop(sliceDSU, curX + colums);
                                if (topId != curTopId) {
                                    // merge
                                    numMerge++;
                                    sliceDSU[topId] = curTopId;
                                }
                            }

                        }
                    }
                }
//            System.out.println();
                for (int x = 0; x < colums; x++) {
                    if (sliceDSU[x + colums] != -1) {
                        int top = findTop(sliceDSU, x + colums);
                        sliceDSU[x + colums] = top;
                    }
                }
                for (int x = 0; x < colums; x++) {
                    if (sliceDSU[x + colums] != -1) {
                        sliceDSU[x] = sliceDSU[x + colums] - colums;
                    }
                }
                for (int x = colums; x < colums * 2; x++) {
                    sliceDSU[x] = -1;
                }
            }
            out.printLine(numBits - numMerge);
        }

        private int findTop(int[] sliceDSU, int i) {
            int top = i;
            while (sliceDSU[top] != top) {
                top = sliceDSU[top];
            }
            while (sliceDSU[i] != top) {
                i = sliceDSU[i];
                sliceDSU[i] = top;
            }
            return top;
        }

        private int getChValue(char ch) {
            if (ch >= '0' && ch <= '9') {
                return ch - '0';
            } else {
                return ch - 'A' + 10;
            }
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private InputReader.SpaceCharFilter filter;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public int readInt() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public char readCharacter() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            return (char) c;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void close() {
            writer.close();
        }

        public void printLine(int i) {
            writer.println(i);
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author Fedor Poschmann (fedor.poschmann@gmail.com)
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        TaskE solver = new TaskE();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskE {
        public void solve(int testNumber, InputReader in, OutputWriter out) {
            int n = in.readInt(); // 2 << 12
            int m = in.readInt(); // 2 << 14
            TaskE.SliceDSU sliceDSU = new TaskE.SliceDSU(m);
            int sumBits = 0;
            int sumMerge = 0;
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m / 4; j++) {
                    char ch = in.readCharacter();
                    int val = (ch >= 'A') ? ch - 'A' + 10 : ch - '0';
                    for (int numBit = 3; numBit >= 0; numBit--) {
                        int x = (j * 4) + (3 - numBit);
                        int pos = m + x;
                        if (((val >> numBit) & 1) == 1) {
                            sliceDSU.set(pos);
                            sumBits++;// num bits
                            if (x > 0) {
                                // check left
                                if (sliceDSU.isSet(pos - 1)) {
                                    sliceDSU.data[pos] = pos - 1;
                                    sumMerge++; //merge
                                }
                            }
                            // check up
                            if (sliceDSU.isSet(pos - m)) {
                                int curTop = sliceDSU.findTop(pos);
                                int upTop = sliceDSU.findTop(pos - m);
                                if (curTop != upTop) {
                                    sliceDSU.data[upTop] = curTop;
                                    sumMerge++;
                                }
                            }
                        } else {
                            sliceDSU.unSet(pos);
                        }
                    }
                }
                sliceDSU.updateIDs();
            }
            out.printLine(sumBits - sumMerge);
        }

        static class SliceDSU {
            int[] data;

            public SliceDSU(int colums) {
                data = new int[colums * 2];
                for (int i = 0; i < data.length; i++) {
                    data[i] = -1;
                }
            }

            int findTop(int i) {
                int res = i;
                while (data[res] != res) {
                    res = data[res];
                }
                while (data[i] != i) {
                    int tmp = i;
                    i = data[i];
                    data[tmp] = res;
                }
                return res;
            }

            void updateIDs() {
                int rowSize = data.length / 2;

                for (int i = 0; i < rowSize; i++) {
                    if (data[i + rowSize] != -1 && data[i + rowSize] < rowSize) {
                        throw new RuntimeException("updateId illegal top");
                    }
                    data[i] = (data[i + rowSize] == -1) ? -1 : data[i + rowSize] - rowSize;
                }
            }

            boolean isSet(int i) {
                return data[i] != -1;
            }

            void set(int i) {
                data[i] = i;
            }

            void unSet(int i) {
                data[i] = -1;
            }

        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private InputReader.SpaceCharFilter filter;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public int readInt() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public char readCharacter() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            return (char) c;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void close() {
            writer.close();
        }

        public void printLine(int i) {
            writer.println(i);
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.List;
import java.io.BufferedWriter;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.BitSet;
import java.util.ArrayList;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author Fedor Poschmann (fedor.poschmann@gmail.com)
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        TaskE solver = new TaskE();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskE {
        public void solve(int testNumber, InputReader in, OutputWriter out) {
            int rows = in.readInt();
            int colums = in.readInt();
            BitSet[] matrix = new BitSet[rows];
            for (int i = 0; i < rows; i++) {
                matrix[i] = new BitSet(colums);
                BitSet curRow = matrix[i];
                for (int j = 0; j < colums / 4; j++) {
                    char ch = in.readCharacter();
                    int mask = getChValue(ch);
                    if ((mask & 1) == 1) {
                        curRow.set(j * 4 + 3);
                    }
                    if (((mask >> 1) & 1) == 1) {
                        curRow.set(j * 4 + 2);
                    }
                    if (((mask >> 2) & 1) == 1) {
                        curRow.set(j * 4 + 1);
                    }
                    if (((mask >> 3) & 1) == 1) {
                        curRow.set(j * 4);
                    }
                }
            }
//        for (int i = 0; i < rows; i++) {
//            for (int j = 0; j < colums; j++) {
//                System.out.print(matrix[i].get(j) ? '1' : '0');
//            }
//            System.out.println();
//        }
            int res = 0;
            for (int i = 0; i < rows; i++) {
                for (int j = 0; j < colums; j++) {
                    if (matrix[i].get(j)) {
                        res += 1;
                        List<TaskE.Point> deque = new ArrayList<>();
                        deque.add(new TaskE.Point(i, j));
                        while (!deque.isEmpty()) {
                            List<TaskE.Point> tmpList = new ArrayList<>();
                            for (TaskE.Point point : deque) {
                                if (matrix[point.row].get(point.col)) {
                                    matrix[point.row].set(point.col, false);
                                    tmpList.addAll(point.getNeighbours(rows, colums));
                                }
                            }
                            deque = tmpList;
                        }
                    }
                }
            }
            out.printLine(res);
        }

        private int getChValue(char ch) {
            if (ch >= '0' && ch <= '9') {
                return ch - '0';
            } else {
                return ch - 'A' + 10;
            }
        }

        static class Point {
            int row;
            int col;

            public Point(int row, int col) {
                this.row = row;
                this.col = col;
            }

            public List<TaskE.Point> getNeighbours(int rows, int colums) {
                List<TaskE.Point> res = new ArrayList<>();
                if (row > 0) res.add(new TaskE.Point(row - 1, col));
                if (row < rows - 1) res.add(new TaskE.Point(row + 1, col));
                if (col > 0) res.add(new TaskE.Point(row, col - 1));
                if (col < colums - 1) res.add(new TaskE.Point(row, col + 1));
                return res;
            }

        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private InputReader.SpaceCharFilter filter;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public int readInt() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public char readCharacter() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            return (char) c;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void close() {
            writer.close();
        }

        public void printLine(int i) {
            writer.println(i);
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author Fedor Poschmann (fedor.poschmann@gmail.com)
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        TaskE solver = new TaskE();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskE {
        public void solve(int testNumber, InputReader in, OutputWriter out) {
            int n = in.readInt();
            int m = in.readInt();
            TaskE.SliceDSU sliceDSU = new TaskE.SliceDSU(m);
            int sumBits = 0;
            int sumMerge = 0;
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m / 4; j++) {
                    char ch = in.readCharacter();
                    int val = (ch >= 'A') ? ch - 'A' + 10 : ch - '0';
                    for (int numBit = 3; numBit >= 0; numBit--) {
                        if (((val >> numBit) & 1) == 1) {
                            int x = (j * 4) + (3 - numBit);
                            int pos = m + x;
                            sliceDSU.set(pos);
                            sumBits++;// num bits
                            if (x > 0) {
                                // check left
                                if (sliceDSU.isSet(pos - 1)) {
                                    sliceDSU.union(pos, pos - 1);
                                    sumMerge++; //merge
                                }
                            }
                            // check up
                            if (sliceDSU.isSet(pos - m) && !sliceDSU.isConnected(pos, pos - m)) {
                                sliceDSU.union(pos, pos - m);
                                sumMerge++;
                            }
                        }
                    }
                }
                sliceDSU.updateIDs();
            }
            out.printLine(sumBits - sumMerge);
        }

        static class SliceDSU {
            int[] data;

            public SliceDSU(int colums) {
                data = new int[colums * 2];
                for (int i = 0; i < data.length; i++) {
                    data[i] = -1;
                }
            }

            int findTop(int i) {
                int res = i;
                while (data[res] != res) {
                    res = data[res];
                }
                while (data[i] != i) {
                    int tmp = i;
                    i = data[i];
                    data[tmp] = res;
                }
                return res;
            }

            void union(int a, int b) {
                int topA = findTop(a);
                int topB = findTop(b);
                if (topA > topB) {
                    data[topB] = topA;
                } else {
                    data[topA] = topB;
                }
            }

            boolean isConnected(int a, int b) {
                return findTop(a) == findTop(b);
            }

            void updateIDs() {
                int rowSize = data.length / 2;
                for (int i = 0; i < data.length; i++) {
                    if (isSet(i)) {
                        data[i] = findTop(i);
                    }
                }

                for (int i = 0; i < rowSize; i++) {
                    if (data[i + rowSize] != -1 && data[i + rowSize] < rowSize) {
                        throw new RuntimeException("updateId illegal top");
                    }
                    data[i] = (data[i + rowSize] == -1) ? -1 : data[i + rowSize] - rowSize;
                }
                for (int i = rowSize; i < data.length; i++) {
                    data[i] = -1;
                }
            }

            boolean isSet(int i) {
                return data[i] != -1;
            }

            void set(int i) {
                data[i] = i;
            }

        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private InputReader.SpaceCharFilter filter;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public int readInt() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public char readCharacter() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            return (char) c;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void close() {
            writer.close();
        }

        public void printLine(int i) {
            writer.println(i);
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.BitSet;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author Fedor Poschmann (fedor.poschmann@gmail.com)
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        OutputWriter out = new OutputWriter(outputStream);
        TaskE solver = new TaskE();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskE {
        public void solve(int testNumber, InputReader in, OutputWriter out) {
            int rows = in.readInt();
            int colums = in.readInt();
            BitSet[] matrix = new BitSet[rows];
            for (int i = 0; i < rows; i++) {
                matrix[i] = new BitSet(colums);
                BitSet curRow = matrix[i];
                for (int j = 0; j < colums / 4; j++) {
                    char ch = in.readCharacter();
                    int mask = getChValue(ch);
                    if ((mask & 1) == 1) {
                        curRow.set(j * 4 + 3);
                    }
                    if (((mask >> 1) & 1) == 1) {
                        curRow.set(j * 4 + 2);
                    }
                    if (((mask >> 2) & 1) == 1) {
                        curRow.set(j * 4 + 1);
                    }
                    if (((mask >> 3) & 1) == 1) {
                        curRow.set(j * 4);
                    }
                }
            }
            for (int i = 0; i < rows; i++) {
                for (int j = 0; j < colums; j++) {
                    System.out.print(matrix[i].get(j) ? '1' : '0');
                }
                System.out.println();
            }
            int res = 0;
            for (int i = 0; i < rows; i++) {
                for (int j = 0; j < colums; j++) {
                    if (matrix[i].get(j)) {
                        res += 1;
                        List<TaskE.Point> deque = new ArrayList<>();
                        deque.add(new TaskE.Point(i, j));
                        while (!deque.isEmpty()) {
                            List<TaskE.Point> tmpList = new ArrayList<>();
                            for (TaskE.Point point : deque) {
                                if (matrix[point.row].get(point.col)) {
                                    matrix[point.row].set(point.col, false);
                                    tmpList.addAll(point.getNeighbours(rows, colums));
                                }
                            }
                            deque = tmpList;
                        }
                    }
                }
            }
            out.printLine(res);
        }

        private int getChValue(char ch) {
            if (ch >= '0' && ch <= '9') {
                return ch - '0';
            } else {
                return ch - 'A' + 10;
            }
        }

        static class Point {
            int row;
            int col;

            public Point(int row, int col) {
                this.row = row;
                this.col = col;
            }

            public List<TaskE.Point> getNeighbours(int rows, int colums) {
                List<TaskE.Point> res = new ArrayList<>();
                if (row > 0) res.add(new TaskE.Point(row - 1, col));
                if (row < rows - 1) res.add(new TaskE.Point(row + 1, col));
                if (col > 0) res.add(new TaskE.Point(row, col - 1));
                if (col < colums - 1) res.add(new TaskE.Point(row, col + 1));
                return res;
            }

        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private InputReader.SpaceCharFilter filter;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (numChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public int readInt() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            if (filter != null) {
                return filter.isSpaceChar(c);
            }
            return isWhitespace(c);
        }

        public static boolean isWhitespace(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public char readCharacter() {
            int c = read();
            while (isSpaceChar(c)) {
                c = read();
            }
            return (char) c;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);

        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void close() {
            writer.close();
        }

        public void printLine(int i) {
            writer.println(i);
        }

    }
}


import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.InputMismatchException;
import java.util.List;

public class Main {

	private static final int MAXN = 5000;
	private static final String NO = "NO";
	private static final String YES = "YES";
	InputStream is;
	PrintWriter out;
	String INPUT = "";

	private static final long MOD = 1000000007L;
	int[] p;

	int find(int x) {
		if (p[x] == x)
			return x;
		else
			return p[x] = find(p[x]);
	}

	long cnt = 0;

	private void merge(int i, int j) {
		int pi = find(i);
		int pj = find(j);
		if (pi != pj) {
			p[pi] = pj;
			cnt--;
		}
	}

	void solve() {
		int N = ni();
		int M = ni();
		p = new int[2 * M + 1];
		int pos[][] = new int[2][M];
		for (int r = 0; r < 2; r++)
			for (int c = 0; c < M; c++)
				pos[r][c] = r * M + c + 1;
//		tr(pos);
		int now = 0;
		BitSet prev = new BitSet();
		while (N-- > 0) {
			BitSet cur = new BitSet();
			char[] a = ns().toCharArray();
			for (int c = 0; c < M / 4; c++) {
				int n = a[c] >= 'A' ? a[c] - 'A' + 10 : a[c] - '0';
				for (int i = 0; i < 4; i++, n >>= 1)
					if ((n & 1) != 0)
						cur.set(4 * c + 3 - i);
			}
//			tr(N, a, cur);
			for (int c = 0; c < M; c++) {
				p[pos[now][c]] = pos[now][c];
				if (cur.get(c)) {
					cnt++;
					if (cur.get(c) && prev.get(c))
						merge(pos[1 ^ now][c], pos[now][c]);
					if (c > 0)
						if (cur.get(c - 1) && cur.get(c))
							merge(pos[now][c - 1], pos[now][c]);
				}
			}
			prev = cur;
			now ^= 1;
		}
		out.print(cnt);
	}

	long power(long a, long b) {
		long x = 1, y = a;
		while (b > 0) {
			if (b % 2 != 0) {
				x = (x * y) % MOD;
			}
			y = (y * y) % MOD;
			b /= 2;
		}
		return x % MOD;
	}

	private long gcd(long a, long b) {
		while (a != 0) {
			long tmp = b % a;
			b = a;
			a = tmp;
		}
		return b;
	}

	void run() throws Exception {
		is = INPUT.isEmpty() ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		out = new PrintWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		if (!INPUT.isEmpty())
			tr(System.currentTimeMillis() - s + "ms");
	}

	public static void main(String[] args) throws Exception {
		new Main().run();
	}

	private byte[] inbuf = new byte[1024];
	public int lenbuf = 0, ptrbuf = 0;
	private boolean vis[];

	private int readByte() {
		if (lenbuf == -1)
			throw new InputMismatchException();
		if (ptrbuf >= lenbuf) {
			ptrbuf = 0;
			try {
				lenbuf = is.read(inbuf);
			} catch (IOException e) {
				throw new InputMismatchException();
			}
			if (lenbuf <= 0)
				return -1;
		}
		return inbuf[ptrbuf++];
	}

	private boolean isSpaceChar(int c) {
		return !(c >= 33 && c <= 126);
	}

	private int skip() {
		int b;
		while ((b = readByte()) != -1 && isSpaceChar(b))
			;
		return b;
	}

	private double nd() {
		return Double.parseDouble(ns());
	}

	private char nc() {
		return (char) skip();
	}

	private String ns() {
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while (!(isSpaceChar(b))) { // when nextLine, (isSpaceChar(b) && b != '
									// ')
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	private char[] ns(int n) {
		char[] buf = new char[n];
		int b = skip(), p = 0;
		while (p < n) {
			if (!(isSpaceChar(b)))
				buf[p++] = (char) b;
			b = readByte();
		}
		return n == p ? buf : Arrays.copyOf(buf, p);
	}

	private char[][] nm(int n, int m) {
		char[][] map = new char[n][];
		for (int i = 0; i < n; i++)
			map[i] = ns(m);
		return map;
	}

	private int[] na(int n) {
		int[] a = new int[n];
		for (int i = 0; i < n; i++)
			a[i] = ni();
		return a;
	}

	private List<Integer> na2(int n) {
		List<Integer> a = new ArrayList<Integer>();
		for (int i = 0; i < n; i++)
			a.add(ni());
		return a;
	}

	private int[][] na(int n, int m) {
		int[][] a = new int[n][];
		for (int i = 0; i < n; i++)
			a[i] = na(m);
		return a;
	}

	private int ni() {
		int num = 0, b;
		boolean minus = false;
		while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'))
			;
		if (b == '-') {
			minus = true;
			b = readByte();
		}

		while (true) {
			if (b >= '0' && b <= '9') {
				num = num * 10 + (b - '0');
			} else {
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private long[] nl(int n) {
		long[] a = new long[n];
		for (int i = 0; i < n; i++)
			a[i] = nl();
		return a;
	}

	private long nl() {
		long num = 0;
		int b;
		boolean minus = false;
		while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'))
			;
		if (b == '-') {
			minus = true;
			b = readByte();
		}

		while (true) {
			if (b >= '0' && b <= '9') {
				num = num * 10 + (b - '0');
			} else {
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private static void tr(Object... o) {
		System.out.println(Arrays.deepToString(o));
	}
}


import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.InputMismatchException;
import java.util.List;

public class Main {

	private static final int MAXN = 5000;
	private static final String NO = "NO";
	private static final String YES = "YES";
	InputStream is;
	PrintWriter out;
	String INPUT = "";

	private static final long MOD = 1000000007L;
	int[] p;

	int find(int x) {
		if (p[x] == x)
			return x;
		else
			return p[x] = find(p[x]);
	}

	long cnt = 0;

	private void merge(int i, int j) {
		int pi = find(i);
		int pj = find(j);
		if (pi != pj) {
			p[pi] = pj;
			cnt--;
		}
	}

	void solve() {
		int N = ni();
		int M = ni();
		p = new int[2 * M + 1];
		int pos[][] = new int[2][M];
		for (int r = 0; r < 2; r++)
			for (int c = 0; c < M; c++)
				pos[r][c] = r * M + c + 1;
//		tr(pos);
		int now = 0;
		BigInteger prev = BigInteger.ZERO;
		while (N-- > 0) {
			BigInteger cur = new BigInteger(ns(), 16);
			for (int c = 0; c < M; c++) {
				p[pos[now][c]] = pos[now][c];
				if (!cur.testBit(c))
					continue;
				cnt++;
				if (cur.testBit(c) && prev.testBit(c))
					merge(pos[1 ^ now][c], pos[now][c]);
				if (c > 0)
					if (cur.testBit(c - 1) && cur.testBit(c))
						merge(pos[now][c - 1], pos[now][c]);
			}
			prev = cur;
		}
		out.print(cnt);
	}

	long power(long a, long b) {
		long x = 1, y = a;
		while (b > 0) {
			if (b % 2 != 0) {
				x = (x * y) % MOD;
			}
			y = (y * y) % MOD;
			b /= 2;
		}
		return x % MOD;
	}

	private long gcd(long a, long b) {
		while (a != 0) {
			long tmp = b % a;
			b = a;
			a = tmp;
		}
		return b;
	}

	void run() throws Exception {
		is = INPUT.isEmpty() ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		out = new PrintWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		if (!INPUT.isEmpty())
			tr(System.currentTimeMillis() - s + "ms");
	}

	public static void main(String[] args) throws Exception {
		new Main().run();
	}

	private byte[] inbuf = new byte[1024];
	public int lenbuf = 0, ptrbuf = 0;
	private boolean vis[];

	private int readByte() {
		if (lenbuf == -1)
			throw new InputMismatchException();
		if (ptrbuf >= lenbuf) {
			ptrbuf = 0;
			try {
				lenbuf = is.read(inbuf);
			} catch (IOException e) {
				throw new InputMismatchException();
			}
			if (lenbuf <= 0)
				return -1;
		}
		return inbuf[ptrbuf++];
	}

	private boolean isSpaceChar(int c) {
		return !(c >= 33 && c <= 126);
	}

	private int skip() {
		int b;
		while ((b = readByte()) != -1 && isSpaceChar(b))
			;
		return b;
	}

	private double nd() {
		return Double.parseDouble(ns());
	}

	private char nc() {
		return (char) skip();
	}

	private String ns() {
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while (!(isSpaceChar(b))) { // when nextLine, (isSpaceChar(b) && b != '
									// ')
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	private char[] ns(int n) {
		char[] buf = new char[n];
		int b = skip(), p = 0;
		while (p < n) {
			if (!(isSpaceChar(b)))
				buf[p++] = (char) b;
			b = readByte();
		}
		return n == p ? buf : Arrays.copyOf(buf, p);
	}

	private char[][] nm(int n, int m) {
		char[][] map = new char[n][];
		for (int i = 0; i < n; i++)
			map[i] = ns(m);
		return map;
	}

	private int[] na(int n) {
		int[] a = new int[n];
		for (int i = 0; i < n; i++)
			a[i] = ni();
		return a;
	}

	private List<Integer> na2(int n) {
		List<Integer> a = new ArrayList<Integer>();
		for (int i = 0; i < n; i++)
			a.add(ni());
		return a;
	}

	private int[][] na(int n, int m) {
		int[][] a = new int[n][];
		for (int i = 0; i < n; i++)
			a[i] = na(m);
		return a;
	}

	private int ni() {
		int num = 0, b;
		boolean minus = false;
		while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'))
			;
		if (b == '-') {
			minus = true;
			b = readByte();
		}

		while (true) {
			if (b >= '0' && b <= '9') {
				num = num * 10 + (b - '0');
			} else {
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private long[] nl(int n) {
		long[] a = new long[n];
		for (int i = 0; i < n; i++)
			a[i] = nl();
		return a;
	}

	private long nl() {
		long num = 0;
		int b;
		boolean minus = false;
		while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'))
			;
		if (b == '-') {
			minus = true;
			b = readByte();
		}

		while (true) {
			if (b >= '0' && b <= '9') {
				num = num * 10 + (b - '0');
			} else {
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private static void tr(Object... o) {
		System.out.println(Arrays.deepToString(o));
	}
}


import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.InputMismatchException;
import java.util.List;

public class Main {

	private static final int MAXN = 5000;
	private static final String NO = "NO";
	private static final String YES = "YES";
	InputStream is;
	PrintWriter out;
	String INPUT = "";

	private static final long MOD = 1000000007L;
	int[] p;

	int find(int x) {
		if (p[x] == x)
			return x;
		else
			return p[x] = find(p[x]);
	}

	long cnt = 0;

	private void merge(int i, int j) {
		int pi = find(i);
		int pj = find(j);
		if (pi != pj) {
			p[pi] = pj;
			cnt--;
		}
	}

	void solve() {
		int N = ni();
		int M = ni();
		p = new int[2 * M + 1];
		int pos[][] = new int[2][M];
		for (int r = 0; r < 2; r++)
			for (int c = 0; c < M; c++)
				pos[r][c] = r * M + c + 1;
//		tr(pos);
		int now = 0;
		int[] prev = new int[M];
		while (N-- > 0) {
			int[] cur = new int[M];
			char[] a = ns().toCharArray();
			for (int c = 0; c < M / 4; c++) {
				int n = a[c] >= 'A' ? a[c] - 'A' + 10 : a[c] - '0';
				for (int i = 0; i < 4; i++, n >>= 1)
					if ((n & 1) != 0)
						cur[4 * c + 3 - i] = 1;
			}
//			tr(N, a, cur);
			for (int c = 0; c < M; c++) {
				p[pos[now][c]] = pos[now][c];
				if (cur[c] == 1) {
					cnt++;
					if (cur[c] == 1 && prev[c] == 1)
						merge(pos[1 ^ now][c], pos[now][c]);
					if (c > 0)
						if (cur[c - 1] == 1 && cur[c] == 1)
							merge(pos[now][c - 1], pos[now][c]);
				}
			}
			prev = cur;
			now ^= 1;
		}
		out.print(cnt);
	}

	long power(long a, long b) {
		long x = 1, y = a;
		while (b > 0) {
			if (b % 2 != 0) {
				x = (x * y) % MOD;
			}
			y = (y * y) % MOD;
			b /= 2;
		}
		return x % MOD;
	}

	private long gcd(long a, long b) {
		while (a != 0) {
			long tmp = b % a;
			b = a;
			a = tmp;
		}
		return b;
	}

	void run() throws Exception {
		is = INPUT.isEmpty() ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		out = new PrintWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		if (!INPUT.isEmpty())
			tr(System.currentTimeMillis() - s + "ms");
	}

	public static void main(String[] args) throws Exception {
		new Main().run();
	}

	private byte[] inbuf = new byte[1024];
	public int lenbuf = 0, ptrbuf = 0;
	private boolean vis[];

	private int readByte() {
		if (lenbuf == -1)
			throw new InputMismatchException();
		if (ptrbuf >= lenbuf) {
			ptrbuf = 0;
			try {
				lenbuf = is.read(inbuf);
			} catch (IOException e) {
				throw new InputMismatchException();
			}
			if (lenbuf <= 0)
				return -1;
		}
		return inbuf[ptrbuf++];
	}

	private boolean isSpaceChar(int c) {
		return !(c >= 33 && c <= 126);
	}

	private int skip() {
		int b;
		while ((b = readByte()) != -1 && isSpaceChar(b))
			;
		return b;
	}

	private double nd() {
		return Double.parseDouble(ns());
	}

	private char nc() {
		return (char) skip();
	}

	private String ns() {
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while (!(isSpaceChar(b))) { // when nextLine, (isSpaceChar(b) && b != '
									// ')
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	private char[] ns(int n) {
		char[] buf = new char[n];
		int b = skip(), p = 0;
		while (p < n) {
			if (!(isSpaceChar(b)))
				buf[p++] = (char) b;
			b = readByte();
		}
		return n == p ? buf : Arrays.copyOf(buf, p);
	}

	private char[][] nm(int n, int m) {
		char[][] map = new char[n][];
		for (int i = 0; i < n; i++)
			map[i] = ns(m);
		return map;
	}

	private int[] na(int n) {
		int[] a = new int[n];
		for (int i = 0; i < n; i++)
			a[i] = ni();
		return a;
	}

	private List<Integer> na2(int n) {
		List<Integer> a = new ArrayList<Integer>();
		for (int i = 0; i < n; i++)
			a.add(ni());
		return a;
	}

	private int[][] na(int n, int m) {
		int[][] a = new int[n][];
		for (int i = 0; i < n; i++)
			a[i] = na(m);
		return a;
	}

	private int ni() {
		int num = 0, b;
		boolean minus = false;
		while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'))
			;
		if (b == '-') {
			minus = true;
			b = readByte();
		}

		while (true) {
			if (b >= '0' && b <= '9') {
				num = num * 10 + (b - '0');
			} else {
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private long[] nl(int n) {
		long[] a = new long[n];
		for (int i = 0; i < n; i++)
			a[i] = nl();
		return a;
	}

	private long nl() {
		long num = 0;
		int b;
		boolean minus = false;
		while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'))
			;
		if (b == '-') {
			minus = true;
			b = readByte();
		}

		while (true) {
			if (b >= '0' && b <= '9') {
				num = num * 10 + (b - '0');
			} else {
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private static void tr(Object... o) {
		System.out.println(Arrays.deepToString(o));
	}
}


import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.InputMismatchException;
import java.util.List;

public class Main {

	private static final int MAXN = 5000;
	private static final String NO = "NO";
	private static final String YES = "YES";
	InputStream is;
	PrintWriter out;
	String INPUT = "";

	private static final long MOD = 1000000007L;
	int[] p;

	int find(int x) {
		if (p[x] == x)
			return x;
		else
			return p[x] = find(p[x]);
	}

	long cnt = 0;

	private void merge(int i, int j) {
		int pi = find(i);
		int pj = find(j);
		if (pi != pj) {
			p[pi] = pj;
			cnt--;
		}
	}

	void solve() {
		int N = ni();
		int M = ni();
		p = new int[2 * M + 1];
		int pos[][] = new int[2][M];
		for (int r = 0; r < 2; r++)
			for (int c = 0; c < M; c++)
				pos[r][c] = r * M + c + 1;
//		tr(pos);
		int now = 0;
		BigInteger prev = BigInteger.ZERO;
		while (N-- > 0) {
			BigInteger cur = new BigInteger(ns(), 16);
			for (int c = 0; c < M; c++) {
				p[pos[now][c]] = pos[now][c];
				if (cur.testBit(c)) {
					cnt++;
					if (cur.testBit(c) && prev.testBit(c))
						merge(pos[1 ^ now][c], pos[now][c]);
					if (c > 0)
						if (cur.testBit(c - 1) && cur.testBit(c))
							merge(pos[now][c - 1], pos[now][c]);
				}
			}
			prev = cur;
			now ^= 1;
		}
		out.print(cnt);
	}

	long power(long a, long b) {
		long x = 1, y = a;
		while (b > 0) {
			if (b % 2 != 0) {
				x = (x * y) % MOD;
			}
			y = (y * y) % MOD;
			b /= 2;
		}
		return x % MOD;
	}

	private long gcd(long a, long b) {
		while (a != 0) {
			long tmp = b % a;
			b = a;
			a = tmp;
		}
		return b;
	}

	void run() throws Exception {
		is = INPUT.isEmpty() ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		out = new PrintWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		if (!INPUT.isEmpty())
			tr(System.currentTimeMillis() - s + "ms");
	}

	public static void main(String[] args) throws Exception {
		new Main().run();
	}

	private byte[] inbuf = new byte[1024];
	public int lenbuf = 0, ptrbuf = 0;
	private boolean vis[];

	private int readByte() {
		if (lenbuf == -1)
			throw new InputMismatchException();
		if (ptrbuf >= lenbuf) {
			ptrbuf = 0;
			try {
				lenbuf = is.read(inbuf);
			} catch (IOException e) {
				throw new InputMismatchException();
			}
			if (lenbuf <= 0)
				return -1;
		}
		return inbuf[ptrbuf++];
	}

	private boolean isSpaceChar(int c) {
		return !(c >= 33 && c <= 126);
	}

	private int skip() {
		int b;
		while ((b = readByte()) != -1 && isSpaceChar(b))
			;
		return b;
	}

	private double nd() {
		return Double.parseDouble(ns());
	}

	private char nc() {
		return (char) skip();
	}

	private String ns() {
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while (!(isSpaceChar(b))) { // when nextLine, (isSpaceChar(b) && b != '
									// ')
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	private char[] ns(int n) {
		char[] buf = new char[n];
		int b = skip(), p = 0;
		while (p < n) {
			if (!(isSpaceChar(b)))
				buf[p++] = (char) b;
			b = readByte();
		}
		return n == p ? buf : Arrays.copyOf(buf, p);
	}

	private char[][] nm(int n, int m) {
		char[][] map = new char[n][];
		for (int i = 0; i < n; i++)
			map[i] = ns(m);
		return map;
	}

	private int[] na(int n) {
		int[] a = new int[n];
		for (int i = 0; i < n; i++)
			a[i] = ni();
		return a;
	}

	private List<Integer> na2(int n) {
		List<Integer> a = new ArrayList<Integer>();
		for (int i = 0; i < n; i++)
			a.add(ni());
		return a;
	}

	private int[][] na(int n, int m) {
		int[][] a = new int[n][];
		for (int i = 0; i < n; i++)
			a[i] = na(m);
		return a;
	}

	private int ni() {
		int num = 0, b;
		boolean minus = false;
		while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'))
			;
		if (b == '-') {
			minus = true;
			b = readByte();
		}

		while (true) {
			if (b >= '0' && b <= '9') {
				num = num * 10 + (b - '0');
			} else {
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private long[] nl(int n) {
		long[] a = new long[n];
		for (int i = 0; i < n; i++)
			a[i] = nl();
		return a;
	}

	private long nl() {
		long num = 0;
		int b;
		boolean minus = false;
		while ((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'))
			;
		if (b == '-') {
			minus = true;
			b = readByte();
		}

		while (true) {
			if (b >= '0' && b <= '9') {
				num = num * 10 + (b - '0');
			} else {
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private static void tr(Object... o) {
		System.out.println(Arrays.deepToString(o));
	}
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author svilen.marchev@gmail.com
 */
public class Main {
  public static void main(String[] args) {
    InputStream inputStream = System.in;
    OutputStream outputStream = System.out;
    InputReader in = new InputReader(inputStream);
    PrintWriter out = new PrintWriter(outputStream);
    TaskE solver = new TaskE();
    solver.solve(1, in, out);
    out.close();
  }

  static class TaskE {
    SvLogger logger = new SvLogger().setEnabled(false);
    int n;
    int m;
    int[] parent;

    int convertCharToBitmask(char c) {
      if ('0' <= c && c <= '9') {
        return c - '0';
      }
      return c - 'A' + 10;
    }

    int getRoot(int i) {
      int root = i;
      while (parent[root] != -1) {
        root = parent[root];
      }
      while (i != root) {
        int oldparent = parent[i];
        parent[i] = root;
        i = oldparent;
      }
      return root;
    }

    int join(int i, int j) {
      int rooti = getRoot(i);
      int rootj = getRoot(j);
      if (rooti == rootj) {
        return 0;
      }
      parent[rootj] = rooti;
      return 1;
    }

    void readRow(byte[] row, InputReader in) {
      for (int colblock = 0; colblock < m / 4; ++colblock) {
        int block = convertCharToBitmask(in.readCharacter());
        for (int c = 0; c < 4; ++c) {
          row[colblock * 4 + c] = ((block >>> (3 - c)) & 1) == 1 ? (byte) 1 : 0;
        }
      }
    }

    public void solve(int testNumber, InputReader in, PrintWriter out) {
      n = in.readInt();
      m = in.readInt();

      byte[][] rows = new byte[2][m];

      // DSU
      parent = new int[2 * m];
      Arrays.fill(parent, -1);

      int[] remap = new int[2 * m];
      int[] rootsInCurRow = new int[m];

      int numJoins = 0;
      int numOnes = 0;

      for (int i = 0; i < n; ++i) {
        byte[] currow = rows[i % 2];
        byte[] prevrow = rows[(i + 1) % 2];
        readRow(currow, in);
        logger.p(Arrays.toString(currow));

        for (int j = 0; j < m; ++j) {
          if (currow[j] == 0) continue;
          numOnes++;
          if (i > 0 && prevrow[j] == 1) numJoins += join(j, m + j);
          if (j > 0 && currow[j - 1] == 1) numJoins += join(m + j - 1, m + j);
        }

        logger.p("parent before %s", Arrays.toString(parent));

        // Save the roots of each element of the cur row, before we remove the elements of the
        // previous row.
        for (int j = 0; j < m; ++j) {
          rootsInCurRow[j] = getRoot(m + j);
        }
        logger.p("rootsInCurRow: %s", Arrays.toString(rootsInCurRow));
        Arrays.fill(remap, -1);
        for (int j = 0; j < m; ++j) {
          int curroot = rootsInCurRow[j];
          if (remap[curroot] == -1) {
            remap[curroot] = j;
            parent[j] = -1;
          } else {
            parent[j] = remap[curroot];
          }
        }
        for (int j = 0; j < m; ++j) parent[m + j] = -1;
        logger.p("parent after %s", Arrays.toString(parent));
      }

      out.println(numOnes - numJoins);
    }

  }

  static class InputReader {
    private InputStream stream;
    private byte[] buf = new byte[1024];
    private int curChar;
    private int numChars;
    private InputReader.SpaceCharFilter filter;

    public InputReader(InputStream stream) {
      this.stream = stream;
    }

    public int read() {
      if (numChars == -1) {
        throw new InputMismatchException();
      }
      if (curChar >= numChars) {
        curChar = 0;
        try {
          numChars = stream.read(buf);
        } catch (IOException e) {
          throw new InputMismatchException();
        }
        if (numChars <= 0) {
          return -1;
        }
      }
      return buf[curChar++];
    }

    public int readInt() {
      int c = read();
      while (isSpaceChar(c)) {
        c = read();
      }
      int sgn = 1;
      if (c == '-') {
        sgn = -1;
        c = read();
      }
      int res = 0;
      do {
        if (c < '0' || c > '9') {
          throw new InputMismatchException();
        }
        res *= 10;
        res += c - '0';
        c = read();
      } while (!isSpaceChar(c));
      return res * sgn;
    }

    public boolean isSpaceChar(int c) {
      if (filter != null) {
        return filter.isSpaceChar(c);
      }
      return isWhitespace(c);
    }

    public static boolean isWhitespace(int c) {
      return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
    }

    public char readCharacter() {
      int c = read();
      while (isSpaceChar(c)) {
        c = read();
      }
      return (char) c;
    }

    public interface SpaceCharFilter {
      public boolean isSpaceChar(int ch);

    }

  }

  static class SvLogger {
    private static final String MESSAGE_PREFIX = "> ";
    private boolean enabled = true;
    private boolean printTimeEllapsed = false;
    private long startedTime = System.currentTimeMillis();

    public SvLogger setEnabled(boolean enabled) {
      this.enabled = enabled;
      return this;
    }

    public void p(String format, Object... args) {
      if (!enabled) {
        return;
      }
      printMessage(String.format(format, args));
    }

    private void printMessage(String msg) {
      String formattedTime =
          printTimeEllapsed ? " (" + (System.currentTimeMillis() - startedTime) + " ms)" : "";
      System.out.println(MESSAGE_PREFIX + msg + formattedTime);
    }

  }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author svilen.marchev@gmail.com
 */
public class Main {
  public static void main(String[] args) {
    InputStream inputStream = System.in;
    OutputStream outputStream = System.out;
    InputReader in = new InputReader(inputStream);
    PrintWriter out = new PrintWriter(outputStream);
    TaskE solver = new TaskE();
    solver.solve(1, in, out);
    out.close();
  }

  static class TaskE {
    int n;
    int m;
    int[] parent;

    int convertCharToBitmask(char c) {
      if ('0' <= c && c <= '9') {
        return c - '0';
      }
      return c - 'A' + 10;
    }

    int getRoot(int i) {
      int root = i;
      while (parent[root] != -1) {
        root = parent[root];
      }
      while (i != root) {
        int oldparent = parent[i];
        parent[i] = root;
        i = oldparent;
      }
      return root;
    }

    int join(int i, int j) {
      int rooti = getRoot(i);
      int rootj = getRoot(j);
      if (rooti == rootj) {
        return 0;
      }
      parent[rootj] = rooti;
      return 1;
    }

    void readRow(byte[] row, InputReader in) {
      for (int colblock = 0; colblock < m / 4; ++colblock) {
        int block = convertCharToBitmask(in.readCharacter());
        for (int c = 0; c < 4; ++c) {
          row[colblock * 4 + c] = ((block >>> (3 - c)) & 1) == 1 ? (byte) 1 : 0;
        }
      }
    }

    public void solve(int testNumber, InputReader in, PrintWriter out) {
      n = in.readInt();
      m = in.readInt();

      byte[][] rows = new byte[2][m];

      // DSU
      parent = new int[2 * m];
      Arrays.fill(parent, -1);

      int[] remap = new int[2 * m];
      int[] rootsInCurRow = new int[m];

      int numJoins = 0;
      int numOnes = 0;

      for (int i = 0; i < n; ++i) {
        byte[] currow = rows[i % 2];
        byte[] prevrow = rows[(i + 1) % 2];
        readRow(currow, in);

        for (int j = 0; j < m; ++j) {
          if (currow[j] == 0) continue;
          numOnes++;
          if (i > 0 && prevrow[j] == 1) numJoins += join(j, m + j);
          if (j > 0 && currow[j - 1] == 1) numJoins += join(m + j - 1, m + j);
        }

        // Save the roots of each element of the cur row, before we remove the elements of the
        // previous row.
        for (int j = 0; j < m; ++j) {
          rootsInCurRow[j] = getRoot(m + j);
        }
        Arrays.fill(remap, -1);
        for (int j = 0; j < m; ++j) {
          int curroot = rootsInCurRow[j];
          if (remap[curroot] == -1) {
            remap[curroot] = j;
            parent[j] = -1;
          } else {
            parent[j] = remap[curroot];
          }
        }
        for (int j = 0; j < m; ++j) {
          parent[m + j] = -1;
        }
      }

      out.println(numOnes - numJoins);
    }

  }

  static class InputReader {
    private InputStream stream;
    private byte[] buf = new byte[1024];
    private int curChar;
    private int numChars;
    private InputReader.SpaceCharFilter filter;

    public InputReader(InputStream stream) {
      this.stream = stream;
    }

    public int read() {
      if (numChars == -1) {
        throw new InputMismatchException();
      }
      if (curChar >= numChars) {
        curChar = 0;
        try {
          numChars = stream.read(buf);
        } catch (IOException e) {
          throw new InputMismatchException();
        }
        if (numChars <= 0) {
          return -1;
        }
      }
      return buf[curChar++];
    }

    public int readInt() {
      int c = read();
      while (isSpaceChar(c)) {
        c = read();
      }
      int sgn = 1;
      if (c == '-') {
        sgn = -1;
        c = read();
      }
      int res = 0;
      do {
        if (c < '0' || c > '9') {
          throw new InputMismatchException();
        }
        res *= 10;
        res += c - '0';
        c = read();
      } while (!isSpaceChar(c));
      return res * sgn;
    }

    public boolean isSpaceChar(int c) {
      if (filter != null) {
        return filter.isSpaceChar(c);
      }
      return isWhitespace(c);
    }

    public static boolean isWhitespace(int c) {
      return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
    }

    public char readCharacter() {
      int c = read();
      while (isSpaceChar(c)) {
        c = read();
      }
      return (char) c;
    }

    public interface SpaceCharFilter {
      public boolean isSpaceChar(int ch);

    }

  }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author svilen.marchev@gmail.com
 */
public class Main {
  public static void main(String[] args) {
    InputStream inputStream = System.in;
    OutputStream outputStream = System.out;
    InputReader in = new InputReader(inputStream);
    PrintWriter out = new PrintWriter(outputStream);
    TaskE solver = new TaskE();
    solver.solve(1, in, out);
    out.close();
  }

  static class TaskE {
    int n;
    int m;
    int[] parent;
    int[] size;

    int convertCharToBitmask(char c) {
      if ('0' <= c && c <= '9') {
        return c - '0';
      }
      return c - 'A' + 10;
    }

    int getRoot(int i) {
      int root = i;
      while (parent[root] != -1) {
        root = parent[root];
      }
      while (i != root) {
        int oldparent = parent[i];
        parent[i] = root;
        i = oldparent;
      }
      return root;
    }

    int join(int i, int j) {
      int rooti = getRoot(i);
      int rootj = getRoot(j);
      if (rooti == rootj) {
        return 0;
      }
      if (size[rooti] < size[rootj]) {
        int tmp = rooti;
        rooti = rootj;
        rootj = tmp;
      }
      parent[rootj] = rooti;
      size[rooti] += size[rootj];
      return 1;
    }

    void readRow(byte[] row, InputReader in) {
      for (int colblock = 0; colblock < m / 4; ++colblock) {
        int block = convertCharToBitmask(in.readCharacter());
        for (int c = 0; c < 4; ++c) {
          row[colblock * 4 + c] = ((block >>> (3 - c)) & 1) == 1 ? (byte) 1 : 0;
        }
      }
    }

    public void solve(int testNumber, InputReader in, PrintWriter out) {
      n = in.readInt();
      m = in.readInt();

      byte[][] rows = new byte[2][m];

      // DSU
      parent = new int[2 * m];
      size = new int[2 * m];
      Arrays.fill(parent, -1);
      Arrays.fill(size, 1);

      int[] remap = new int[2 * m];
      int[] rootsInCurRow = new int[m];

      int numJoins = 0;
      int numOnes = 0;

      for (int i = 0; i < n; ++i) {
        byte[] currow = rows[i % 2];
        byte[] prevrow = rows[(i + 1) % 2];
        readRow(currow, in);

        for (int j = 0; j < m; ++j) {
          if (currow[j] == 0) continue;
          numOnes++;
          if (i > 0 && prevrow[j] == 1) numJoins += join(j, m + j);
          if (j > 0 && currow[j - 1] == 1) numJoins += join(m + j - 1, m + j);
        }

        // Save the roots of each element of the cur row, before we remove the elements of the
        // previous row.
        for (int j = 0; j < m; ++j) {
          rootsInCurRow[j] = getRoot(m + j);
        }
        Arrays.fill(remap, -1);
        for (int j = 0; j < m; ++j) {
          int curroot = rootsInCurRow[j];
          if (remap[curroot] == -1) {
            remap[curroot] = j;
            parent[j] = -1;
            size[j] = 1;
          } else {
            parent[j] = remap[curroot];
            size[parent[j]]++;
          }
        }
        for (int j = 0; j < m; ++j) {
          parent[m + j] = -1;
          size[m + j] = 1;
        }
      }

      out.println(numOnes - numJoins);
    }

  }

  static class InputReader {
    private InputStream stream;
    private byte[] buf = new byte[1024];
    private int curChar;
    private int numChars;
    private InputReader.SpaceCharFilter filter;

    public InputReader(InputStream stream) {
      this.stream = stream;
    }

    public int read() {
      if (numChars == -1) {
        throw new InputMismatchException();
      }
      if (curChar >= numChars) {
        curChar = 0;
        try {
          numChars = stream.read(buf);
        } catch (IOException e) {
          throw new InputMismatchException();
        }
        if (numChars <= 0) {
          return -1;
        }
      }
      return buf[curChar++];
    }

    public int readInt() {
      int c = read();
      while (isSpaceChar(c)) {
        c = read();
      }
      int sgn = 1;
      if (c == '-') {
        sgn = -1;
        c = read();
      }
      int res = 0;
      do {
        if (c < '0' || c > '9') {
          throw new InputMismatchException();
        }
        res *= 10;
        res += c - '0';
        c = read();
      } while (!isSpaceChar(c));
      return res * sgn;
    }

    public boolean isSpaceChar(int c) {
      if (filter != null) {
        return filter.isSpaceChar(c);
      }
      return isWhitespace(c);
    }

    public static boolean isWhitespace(int c) {
      return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
    }

    public char readCharacter() {
      int c = read();
      while (isSpaceChar(c)) {
        c = read();
      }
      return (char) c;
    }

    public interface SpaceCharFilter {
      public boolean isSpaceChar(int ch);

    }

  }
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;

int n,m;
int fa[2<<15];
int temp[2<<15];
int a[2<<14];
int b[2<<14];
int get(int x)
{
	if (fa[x] == x) return x;
	return fa[x] = get(fa[x]);
}
char s[2<<14];
int ans = 0;
void merge(int x,int y)
{
	x = get(x);
	y = get(y);
	if (x != y) ans--;
	fa[x] = fa[y] = max(x,y);
}
int main()
{
	cin >> n >> m;
	for (int i = 1;i <= m*2;i++)
		fa[i] = i;
	for (int i = 1;i <= n;i++)
	{
		scanf("%s",s+1);
		int now = 0;
		for (int j = 1;j <= m/4;j++)
		{
			int t;
			if (s[j] >= '0' && s[j] <= '9') t = s[j] - '0';
			if (s[j] >= 'A' && s[j] <= 'F') t = s[j] - 'A' + 10;
			int hehe = 4;
			while (hehe--)
			{
				b[++now] = (t >> hehe)&1;
			}
		}

		for (int j = 1;j <= m;j++)
			if (b[j]) ans++;

		for (int j = 1;j <  m;j++)
			if (b[j] && b[j+1])
				merge(m+j,m+j+1);
		for (int j = 1;j <= m;j++)
			if (b[j] && a[j])
				merge(m+j,j);
		for (int j = 1;j <= m;j++)
			a[j] = b[j];
		for (int j = 1;j <= m * 2;j++)
			temp[j] = get(j);

		for (int j = 1;j <= m * 2;j++)
			fa[j] = j;
		for (int j = 1;j <= m;j++)
			fa[j] = temp[j+m]-m;

	/*	for (int j = 1;j <= m;j++)
			printf("%d",b[j]);
		printf("\n");
		cout << ans << endl;	*/
	}
	cout << ans << endl;
}


#include <cstdio>

using namespace std;
typedef long long ll;
const int MAXM = 20010;
int _w;

int n, m;
char s[MAXM];
int a[MAXM];
int ans;

int turn( int x ) {
	if( x >= '0' && x <= '9' )
		return x - '0';
	if( x >= 'A' && x <= 'F' )
		return x - 'A' + 10;
	return -1;
}

int f[2][MAXM], id;

void fill( int cur ) {
	for( int i = 0; i < m; ++i )
		if( a[i] )
			f[cur][i] = ++id, ++ans;
}

int pa[MAXM<<1];
void dsu_init() {
	for( int i = 1; i <= id; ++i )
		pa[i] = i;
}
int find( int u ) {
	return pa[u] == u ? u : pa[u] = find( pa[u] );
}
bool uni( int u, int v ) {
	u = find(u), v = find(v);
	if( u == v ) return false;
	pa[u] = v;
	return true;
}

void merge( int cur ) {
	dsu_init();
	for( int i = 0; i < m; ++i )
		if( f[cur][i] ) {
			if( f[cur^1][i] )
				if( uni( f[cur][i], f[cur^1][i] ) )
					--ans;
			if( i && f[cur][i-1] )
				if( uni( f[cur][i], f[cur][i-1] ) )
					--ans;
		}
}

int vis[MAXM<<1];
void adjust( int cur ) {
	for( int i = 0; i < m; ++i ) {
		f[cur^1][i] = 0;
		if( f[cur][i] )
			f[cur][i] = find( f[cur][i] );
	}
	for( int i = 1; i <= m*2; ++i )
		vis[i] = 0;
	id = 0;
	for( int i = 0; i < m; ++i )
		if( f[cur][i] ) {
			if( !vis[f[cur][i]] )
				vis[f[cur][i]] = ++id;
			f[cur][i] = vis[f[cur][i]];
		}
}

int main() {
	_w = scanf( "%d%d", &n, &m );
	int cur = 0;
	for( int i = 0; i < n; ++i ) {
		_w = scanf( "%s", s );
		for( int j = 0; j < m; j += 4 ) {
			int x = turn( s[j/4] );
			a[j] = x & 8;
			a[j+1] = x & 4;
			a[j+2] = x & 2;
			a[j+3] = x & 1;
		}
		fill(cur);
		merge(cur);
		adjust(cur);
		cur ^= 1;
	}
	printf( "%d\n", ans );
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define MAXM (1 << 14)

char str[4100];
int id[MAXM], curr[MAXM], aux[MAXM], neighbor[MAXM], ps[MAXM];

void init_set(int sz){
    for(int i=0; i<sz; i++) ps[i] = i;
}

int find_set(int i){
    return ps[i] == i ? i : ps[i] = find_set(ps[i]);
}

void unit_set(int i, int j){
    ps[find_set(i)] = find_set(j);
}

bool is_same_set(int i, int j){
    return find_set(i) == find_set(j);
}

int main(){
    int n, m;
    while(scanf("%d%d", &n, &m) > 0){
        for(int i=0; i<m; i++){
            id[i] = 0;
        }

        int ans = 0;

        while(n--){
            scanf("%s", str);

            for(int i=0; i<m; i+=4){
                int dig = (str[i] >= '0' and str[i] <= '9') ? str[i]-'0' : str[i]-'A'+10;

                for(int j=0, aux=8; j<4; j++, aux>>=1){
                    curr[i+j] = dig/aux;
                    dig %= aux;
                }
            }

            int l = 0;
            int cnt = 0;

            while(l < m){
                if(!curr[l]){
                    l++;
                    continue;
                }

                int r = l;
                while(r < m and curr[r]) r++;

                int qt = 0;
                for(int i=l; i<r; i++){
                    if(id[i]){
                        aux[qt++] = id[i];
                    }
                }

                if(!qt){
                    ans++;
                    neighbor[cnt++] = 0;
                } else {
                    init_set(m+1);

                    for(int i=1; i<qt; i++){
                        if(!is_same_set(aux[0], aux[i])){
                            unit_set(aux[0], aux[i]);
                            ans--;
                        }
                    }

                    neighbor[cnt++] = find_set(aux[0]);
                }

                l = r;
            }

            map<int, int> convert;
            for(int i=0; i<cnt; i++){
                if(neighbor[i] and !convert.count(neighbor[i])){
                    int tmp = convert.size()+1;
                    convert[neighbor[i]] = tmp;
                }
            }

            l = cnt = 0;
            int no_neigh = convert.size()+1;

            while(l < m){
                if(!curr[l]){
                    id[l++] = 0;
                    continue;
                }

                int r = l;
                while(r < m and curr[r]){
                    if(neighbor[cnt]){
                        id[r++] = convert[neighbor[cnt]];
                    } else {
                        id[r++] = no_neigh;
                    }
                }

                if(!neighbor[cnt]) no_neigh++;
                cnt++; l = r;
            }

            //for(int i=0; i<m; i++){
            //    printf("%d ", id[i]);
          //  } printf("\n");
        }

        printf("%d\n", ans);
        //break;
    }
}


#include <bits/stdc++.h>

using namespace std;

#define MAXM (1 << 14)

int n, m, last[MAXM], curr[MAXM];
char str[MAXM];

void read_line(int v[]){
    scanf("%s", str);

    for(int i=0; 4*i<m; i++){
        int num = str[i] >= '0' and str[i] <= '9' ? str[i]-'0' : str[i]-'A'+10;

        for(int j=0; j<4; j++){
            v[4*i+j] = num / (1 << (3-j));
            num %= (1 << (3-j));
        }
    }
}

int ps[2*MAXM+1], change[2*MAXM+1];

void init_set(int sz){
    for(int i=0; i<sz; i++) ps[i] = i;
}

int find_set(int i){
    return ps[i] == i ? i : ps[i] = find_set(ps[i]);
}

bool is_same_set(int i, int j){
    return find_set(i) == find_set(j);
}

void unit_set(int i, int j){
    ps[find_set(i)] = find_set(j);
}

int main(){
    while(scanf("%d%d", &n, &m) > 0){
        read_line(last);

        int cnt = 0, ans = 0;
        for(int i=0; i<m; i++){
            if(last[i]){
                if(i and last[i-1]){
                    last[i] = last[i-1];
                } else {
                    last[i] = ++cnt;
                    ans++;
                }
            }
        }

        n--;
        while(n--){
            read_line(curr);

            for(int i=0; i<m; i++){
                if(curr[i]){
                    if(i and curr[i-1]){
                        curr[i] = curr[i-1];
                    } else {
                        curr[i] = ++cnt;
                        ans++;
                    }
                }
            }

            init_set(cnt+1);

            for(int i=0; i<m; i++){
                if(curr[i] and last[i] and !is_same_set(curr[i], last[i])){
                    unit_set(curr[i], last[i]);
                    ans--;
                }
            }

            for(int i=1; i<=cnt; i++){
                change[i] = 0;
            }

            cnt = 0;
            for(int i=0; i<m; i++){
                last[i] = 0;

                if(curr[i]){
                    if(!change[find_set(curr[i])]){
                        change[find_set(curr[i])] = ++cnt;
                    }
                    last[i] = change[find_set(curr[i])];
                }
            }
        }

        printf("%d\n", ans);
    }
}


#include <bits/stdc++.h>

using namespace std;

#define MAX ((1 << 15)+1)

int n, m, last[MAX], curr[MAX], change[MAX];
char str[MAX];

void read_line(int v[]){
    scanf("%s", str);

    for(int i=0; 4*i<m; i++){
        int num = str[i] >= '0' and str[i] <= '9' ? str[i]-'0' : str[i]-'A'+10;

        for(int j=0; j<4; j++){
            v[i+j] = num / (1 << (3-j));
            num %= (1 << (3-j));
        }
    }
}

int ps[MAX];

void init_set(int sz){
    for(int i=0; i<sz; i++) ps[i] = i;
}

int find_set(int i){
    return ps[i] == i ? i : ps[i] = find_set(ps[i]);
}

void unit_set(int i, int j){
    ps[find_set(i)] = find_set(j);
}

bool is_same_set(int i, int j){
    return find_set(i) == find_set(j);
}

int main(){
    while(scanf("%d%d", &n, &m) > 0){
        read_line(last);

        int cnt = 0, ans = 0;
        for(int i=0; i<m; i++){
            if(last[i]){
                if(i and last[i-1]){
                    last[i] = last[i-1];
                } else {
                    last[i] = ++cnt;
                    ans++;
                }
            }
        }

        n--;
        while(n--){
            read_line(curr);

            for(int i=0; i<m; i++){
                if(curr[i]){
                    if(i and curr[i-1]){
                        curr[i] = curr[i-1];
                    } else {
                        curr[i] = ++cnt;
                        ans++;
                    }
                }
            }

            init_set(cnt+1);

            for(int i=0; i<m; i++){
                if(last[i] and curr[i] and !is_same_set(last[i], curr[i])){
                    unit_set(last[i], curr[i]);
                    ans--;
                }
            }

            for(int i=1; i<=cnt; i++){
                change[i] = 0;
            }

            cnt = 0;
            for(int i=0; i<m; i++){
                if(curr[i]){
                    if(!change[find_set(curr[i])]){
                        change[find_set(curr[i])] = ++cnt;
                    }
                    last[i] = change[find_set(curr[i])];
                }
            }
        }

        printf("%d\n", ans);
    }
}


#include <bits/stdc++.h>

using namespace std;

#define MAXM ((1 << 15)+1)

int n, m, ps[MAXM], last[MAXM], curr[MAXM], change[MAXM], id;
long long ans;
char str[MAXM];

void read_line(int v[]){
    scanf("%s", str);

    for(int i=0; 4*i<m; i++){
        int dig = str[i] >= '0' and str[i] <= '9' ? str[i]-'0' : str[i]-'A'+10;

        for(int j=0; j<4; j++){
            int tmp = dig/(1 << (3-j));
            dig %= (1 << (3-j));

            if(tmp){
                if(4*i+j and v[4*i+j-1]){
                    v[4*i+j] = v[4*i+j-1];
                } else {
                    v[4*i+j] = ++id;
                    ans++;
                }
            } else {
                v[4*i+j] = 0;
            }
        }
    }
}

void init_set(int sz){
    for(int i=0; i<sz; i++) ps[i] = i;
}

int find_set(int i){
    return ps[i] == i ? i : ps[i] = find_set(ps[i]);
}

bool is_same_set(int i, int j){
    return find_set(i) == find_set(j);
}

void unit_set(int i, int j){
    ps[find_set(i)] = find_set(j);
}

int main(){
    while(scanf("%d%d", &n, &m) > 0){
        id = ans = 0;
        read_line(last);

        n--;
        while(n--){
            read_line(curr);

            init_set(id+1);

            for(int i=0; i<m; i++){
                if(curr[i] and last[i] and !is_same_set(last[i], curr[i])){
                    unit_set(last[i], curr[i]);
                    ans--;
                }
            }

            for(int i=1; i<=id; i++){
                change[i] = 0;
            }

            id = 0;
            for(int i=0; i<m; i++){
                if(curr[i]){
                    if(i and curr[i-1]){
                        curr[i] = curr[i-1];
                    } else if(change[curr[i]]){
                        curr[i] = change[curr[i]];
                    } else {
                        change[curr[i]] = ++id;
                        curr[i] = change[curr[i]];
                    }
                } else {
                    curr[i] = 0;
                }
                last[i] = curr[i];
            }
        }

        printf("%lld\n", ans);
 //       break;
    }
}


#include <bits/stdc++.h>

using namespace std;

#define MAXM ((1 << 15)+1)

int n, m, ps[MAXM], last[MAXM], curr[MAXM], change[MAXM], id;
char str[(MAXM >> 2)+1];

void read_line(int v[]){
    scanf("%s", str);

    for(int i=0; 4*i<m; i++){
        int dig = str[i] >= '0' and str[i] <= '9' ? str[i]-'0' : str[i]-'A'+10;

        for(int j=0; j<4; j++){
            int tmp = dig/(1 << (3-j));
            dig %= (1 << (3-j));

            if(tmp){
                if(4*i+j and v[4*i+j-1]){
                    v[4*i+j] = v[4*i+j-1];
                } else {
                    v[4*i+j] = ++id;
                }
            } else {
                v[4*i+j] = 0;
            }
        }
    }
}

void init_set(int sz){
    for(int i=0; i<sz; i++) ps[i] = i;
}

int find_set(int i){
    return ps[i] == i ? i : ps[i] = find_set(ps[i]);
}

bool is_same_set(int i, int j){
    return find_set(i) == find_set(j);
}

void unit_set(int i, int j){
    ps[find_set(i)] = find_set(j);
}

int main(){
    while(scanf("%d%d", &n, &m) > 0){
        id = 0;
        read_line(last);

        long long ans = id;

        n--;
        while(n--){
            ans -= id;
            read_line(curr);
            ans += id;

            init_set(id+1);

            for(int i=0; i<m; i++){
                if(curr[i] and last[i] and !is_same_set(last[i], curr[i])){
                    unit_set(last[i], curr[i]);
                    ans--;
                }
            }

            for(int i=1; i<=id; i++){
                change[i] = 0;
            }

            id = 0;
            for(int i=0; i<m; i++){
                if(curr[i]){
                    if(i and curr[i-1]){
                        curr[i] = curr[i-1];
                    } else if(change[curr[i]]){
                        curr[i] = change[curr[i]];
                    } else {
                        change[curr[i]] = ++id;
                        curr[i] = change[curr[i]];
                    }
                } else {
                    curr[i] = 0;
                }
                last[i] = curr[i];
            }
        }

        printf("%lld\n", ans);
 //       break;
    }
}