Sonya had a birthday recently. She was presented with the matrix of size n× m and consist of lowercase Latin letters. We assume that the rows are numbered by integers from 1 to n from bottom to top, and the columns are numbered from 1 to m from left to right. 

Let's call a submatrix (i_1, j_1, i_2, j_2) (1≤ i_1≤ i_2≤ n; 1≤ j_1≤ j_2≤ m) elements a_{ij} of this matrix, such that i_1≤ i≤ i_2 and j_1≤ j≤ j_2. Sonya states that a submatrix is beautiful if we can independently reorder the characters in each row (not in column) so that all rows and columns of this submatrix form palidroms. 

Let's recall that a string is called palindrome if it reads the same from left to right and from right to left. For example, strings abacaba, bcaacb, a are palindromes while strings abca, acbba, ab are not.

Help Sonya to find the number of beautiful submatrixes. Submatrixes are different if there is an element that belongs to only one submatrix.

Input

The first line contains two integers n and m (1≤ n, m≤ 250) — the matrix dimensions.

Each of the next n lines contains m lowercase Latin letters.

Output

Print one integer — the number of beautiful submatrixes.

Examples

Input


1 3
aba


Output


4

Input


2 3
aca
aac


Output


11

Input


3 5
accac
aaaba
cccaa


Output


43

Note

In the first example, the following submatrixes are beautiful: ((1, 1), (1, 1)); ((1, 2), (1, 2)); ((1, 3), (1, 3)); ((1, 1), (1, 3)).

In the second example, all submatrixes that consist of one element and the following are beautiful: ((1, 1), (2, 1)); ((1, 1), (1, 3)); ((2, 1), (2, 3)); ((1, 1), (2, 3)); ((2, 1), (2, 2)).

Some of the beautiful submatrixes are: ((1, 1), (1, 5)); ((1, 2), (3, 4)); ((1, 1), (3, 5)).

The submatrix ((1, 1), (3, 5)) is beautiful since it can be reordered as:
    
    
      
    accca  
    aabaa  
    accca  
    

In such a matrix every row and every column form palindromes.
import java.io.*;
import java.math.*;
import java.util.*;

public class SonyaAndMatrixBeauty {
	public static void solve(FastIO io) {
		int N = io.nextInt();
		int M = io.nextInt();

		char[][] A = new char[N][];
		for (int i = 0; i < N; ++i) {
			A[i] = io.nextLine().toCharArray();
		}

		StringFreq[] sf = new StringFreq[N];
		for (int i = 0; i < N; ++i) {
			sf[i] = new StringFreq(A[i]);
		}

		long cnt = 0;
		for (int i = 0; i < M; ++i) {
			Freq[] freqs = new Freq[N];
			for (int k = 0; k < N; ++k) {
				freqs[k] = new Freq();
			}
			for (int j = i; j < M; ++j) {
				for (int k = 0; k < N; ++k) {
					freqs[k].increment(A[k][j]);
				}
				int[] arr = ManachersAlgorithm.findPalindromeLengths(freqs);
				for (int k = 1; k < arr.length - 1; ++k) {
					int idx = k >> 1;
					if (freqs[idx].isPalin()) {
						cnt += (arr[k] + 1) >> 1;
					}
				}
			}
		}
		io.println(cnt);
	}

	private static class Freq {
		private static final long[] PRIMES = {30577, 30593, 30631, 30637, 30643, 30649, 30661, 30671, 30677, 30689, 30697, 30703, 30707, 30713, 30727, 30757, 30763, 30773, 30781, 30803, 30809, 30817, 30829, 30839, 30841, 30851};

		private static final Freq EMPTY = new Freq();

		// private long[] freq = new long[4];
		private int[] freq = new int[26];
		private int _odds;

		public boolean isPalin() {
			return _odds <= 1;
		}

		public void increment(char c) {
			int idx = c - 'a';
			++freq[idx];
			if (((freq[idx] & 1)) == 1) {
				++_odds;
			} else {
				--_odds;
			}
			// int num = c - 'a';
			// int idx = num / 7;
			// int pos = num % 7;
			// int bit = pos * 8;
			// freq[idx] += 1 << bit;
			// if (((freq[idx] >> bit) & 1) == 1) {
			// 	++_odds;
			// } else {
			// 	--_odds;
			// }
		}

		public static boolean palinEqual(Freq lhs, Freq rhs) {
			if (!lhs.isPalin() || !rhs.isPalin()) {
				return false;
			}
			return Arrays.equals(lhs.freq, rhs.freq);
		}
	}

	private static class StringFreq {
		public int[][] freq;

		public StringFreq(char[] str) {
			int N = str.length;
			freq = new int[N + 1][26];
			for (int i = 0; i < N; ++i) {
				for (int c = 'a'; c <= 'z'; ++c) {
					freq[i + 1][c - 'a'] = freq[i][c - 'a'];
					if (c == str[i]) {
						++freq[i + 1][c - 'a'];
					}
				}
			}
		}
	}

	public static class ManachersAlgorithm {
		/*
		 * Returns an array containing the longest palindromic substring length at each index.
		 * Input is a string with the boundaries already added.
		 */
		public static int[] findPalindromeLengths(Freq[] s) {
			Freq[] s2 = addBoundaries(s);
			int[] p = new int[s2.length];
			int c = 0, r = 0; // Here the first element in s2 has been processed.
			int m = 0, n = 0; // The walking indices to compare if two elements are the same
			for (int i = 1; i < s2.length; i++) {
				if (i > r) {
					p[i] = 0;
					m = i - 1;
					n = i + 1;
				} else {
					int i2 = c * 2 - i;
					if (p[i2] < (r - i)) {
						p[i] = p[i2];
						m = -1; // This signals bypassing the while loop below.
					} else {
						p[i] = r - i;
						n = r + 1;
						m = i * 2 - n;
					}
				}
				while (m >= 0 && n < s2.length && Freq.palinEqual(s2[m], s2[n])) {
					p[i]++;
					m--;
					n++;
				}
				if ((i + p[i]) > r) {
					c = i;
					r = i + p[i];
				}
			}
			return p;
		}

		private static Freq[] addBoundaries(Freq[] cs) {
			// if (cs == null || cs.length == 0)
			// 	return "||".toCharArray();

			Freq[] cs2 = new Freq[cs.length * 2 + 1];
			for (int i = 0; i < (cs2.length - 1); i = i + 2) {
				cs2[i] = Freq.EMPTY;
				cs2[i + 1] = cs[i / 2];
			}
			cs2[cs2.length - 1] = Freq.EMPTY;
			return cs2;
		}
	}

	public static class FastIO {
		private InputStream reader;
		private PrintWriter writer;

		private byte[] buf = new byte[1024];
		private int curChar;
		private int numChars;

		public FastIO(InputStream r, OutputStream w) {
			reader = r;
			writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(w)));
		}

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

		public String nextLine() {
			int c = read();
			while (isSpaceChar(c))
				c = read();
			StringBuilder res = new StringBuilder();
			do {
				res.appendCodePoint(c);
				c = read();
			} while (!isEndOfLine(c));
			return res.toString();
		}

		public String nextString() {
			int c = read();
			while (isSpaceChar(c))
				c = read();
			StringBuilder res = new StringBuilder();
			do {
				res.appendCodePoint(c);
				c = read();
			} while (!isSpaceChar(c));
			return res.toString();
		}

		public long nextLong() {
			int c = read();
			while (isSpaceChar(c))
				c = read();
			int sgn = 1;
			if (c == '-') {
				sgn = -1;
				c = read();
			}
			long 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 int nextInt() {
			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;
		}

		// TODO: read this byte-by-byte like the other read functions.
		public double nextDouble() {
			return Double.parseDouble(nextString());
		}

		public int[] nextIntArray(int n) {
			return nextIntArray(n, 0);
		}

		public int[] nextIntArray(int n, int off) {
			int[] arr = new int[n + off];
			for (int i = 0; i < n; i++) {
				arr[i + off] = nextInt();
			}
			return arr;
		}

		public long[] nextLongArray(int n) {
			return nextLongArray(n, 0);
		}

		public long[] nextLongArray(int n, int off) {
			long[] arr = new long[n + off];
			for (int i = 0; i < n; i++) {
				arr[i + off] = nextLong();
			}
			return arr;
		}

		private boolean isSpaceChar(int c) {
			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
		}

		private boolean isEndOfLine(int c) {
			return c == '\n' || c == '\r' || c == -1;
		}

		public void print(Object... objects) {
			for (int i = 0; i < objects.length; i++) {
				if (i != 0) {
					writer.print(' ');
				}
				writer.print(objects[i]);
			}
		}

		public void println(Object... objects) {
			print(objects);
			writer.println();
		}

		public void printArray(int[] arr) {
			for (int i = 0; i < arr.length; i++) {
				if (i != 0) {
					writer.print(' ');
				}
				writer.print(arr[i]);
			}
		}

		public void printArray(long[] arr) {
			for (int i = 0; i < arr.length; i++) {
				if (i != 0) {
					writer.print(' ');
				}
				writer.print(arr[i]);
			}
		}

		public void printlnArray(int[] arr) {
			printArray(arr);
			writer.println();
		}

		public void printlnArray(long[] arr) {
			printArray(arr);
			writer.println();
		}

		public void printf(String format, Object... args) {
			print(String.format(format, args));
		}

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

	public static void main(String[] args) {
		FastIO io = new FastIO(System.in, System.out);
		solve(io);
		io.flush();
	}
}
