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.BigInteger;
import java.util.*;

public class D implements Runnable {
	public static void main (String[] args) {new Thread(null, new D(), "_cf", 1 << 28).start();}

	public void run() {
		FastScanner fs = new FastScanner();
//		try { fs = new FastScanner("testdata.out"); } catch (Exception e) {}
		PrintWriter out = new PrintWriter(System.out);
		System.err.println("Go!");
		
//		ManacherLong mana = new ManacherLong();
//		long[] x = {1, 1, 1};
//		System.out.println(Arrays.toString(mana.LPSArray(x)));
//		ManacherString manas = new ManacherString();
//		String s = "abc";

//		long[] txt = {1, 2, 3, 4};
//		long[] cc = Arrays.copyOfRange(txt, 0, 2);
//		txt[0] = 100;
//		System.out.println(Arrays.toString(cc));
//		System.out.println(Arrays.toString(txt));

		long start = System.nanoTime();

		int n = fs.nextInt(), m = fs.nextInt();
		char[][] g = new char[n][m];
		for(int i = 0; i < n; i++) g[i] = fs.next().toCharArray();

		boolean[][][] isPal = new boolean[m+1][n][m];
		for(int i = 0; i < n; i++) {
			for(int j = 0; j < m; j++) {
				char[] str = new char[m];
				int ptr = 0, mask = 0;
				for(int k = j; k < m; k++) {
					str[ptr++] = g[i][k];
					mask ^= 1 << (g[i][k]-'a');
					isPal[ptr][i][j] = Integer.bitCount(mask) <= 1;
				}
			}
		}
		
		long prime = 4219;
		long MOD = BigInteger.valueOf(1000000000 + new Random().nextInt(151265125)).nextProbablePrime().intValue();
		long[] pows = new long[27];
		pows[0] = 1;
		for(int i = 1; i <= 26; i++) {
			pows[i] = (pows[i-1]*prime)%MOD;
		}
//		System.out.println(Arrays.toString(pows));
		
		ManacherLong mc = new ManacherLong();
		
		long res = 0;
		for(int lc = 0; lc < m; lc++) {
			int[][] freq = new int[26][n];
			long[] hashes = new long[n];
			long[] temp = new long[n];
			int ptr = 0;
			for(int rc = lc; rc < m; rc++) {
				ArrayList<long[]> groups = new ArrayList<>();
				int len = rc-lc+1;
				for(int i = 0; i < n; i++) {
					int c = g[i][rc] - 'a';
					hashes[i] -= (pows[c]*freq[c][i]) % MOD;
					while(hashes[i] < 0) hashes[i] += MOD;
					freq[c][i]++;
					hashes[i] += (pows[c]*freq[c][i]) % MOD;
					hashes[i] %= MOD;
					if(!isPal[len][i][lc]) {
						if(ptr > 0) {
							groups.add(Arrays.copyOfRange(temp, 0, ptr));
							ptr = 0;
						}
					}
					else {
						temp[ptr++] = hashes[i];
					}
				}
				if(ptr > 0) {
					groups.add(Arrays.copyOfRange(temp, 0, ptr));
					ptr = 0;
				}
				
//				System.out.printf("[%d, %d]:\n", lc, rc);
//				for(long[] gr : groups) {
//					System.out.println(Arrays.toString(gr));
//				}
//				System.out.println();
				
				for(long[] gr : groups) {
					int[] lps = mc.LPSArray(gr);
					for(int i = 0; i < lps.length; i++) {
						if(i % 2 == 0) {
							res += lps[i]/2;
						}
						else {
							res += lps[i]/2 + (lps[i]%2);
						}
					}
				}
				
			}
		}
		out.println(res);
//		out.println((System.nanoTime()-start)/1000000);

		out.close();
	}

	class ManacherLong {
		long boundaryNumber = (1L<<62);
		int[] LPSArray(long[] s) {
			long[] s2 = addBoundaries(s);
			int[] p = new int[s2.length];
			int c = 0, r = 0, m = 0, n = 0;
			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; }
					else { p[i] = r-i;  n = r+1; m = i*2-n; }
				}
				while (m>=0 && n<s2.length && s2[m]==s2[n]) {
					p[i]++; m--; n++;
				}
				if ((i+p[i])>r) { c = i;  r = i+p[i]; }
			}
			return p;
		}
		long[] addBoundaries(long[] s) {
			long[] cs2 = new long[s.length*2+1];
			for(int i = 0; i < (cs2.length-1); i = i+2) {
				cs2[i] = boundaryNumber; cs2[i+1] = s[i/2];
			}
			cs2[cs2.length-1] = boundaryNumber;
			return cs2;
		}
	}

	class ManacherString {
		char BOUNDARY_CHARACTER = '|';
		int[] LPSArray(String s) {
			char[] s2 = addBoundaries(s.toCharArray());
			int[] p = new int[s2.length]; 
			int c = 0, r = 0, m = 0, n = 0;
			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; }
					else { p[i] = r-i;  n = r+1; m = i*2-n; }
				}
				while (m>=0 && n<s2.length && s2[m]==s2[n]) {
					p[i]++; m--; n++;
				}
				if ((i+p[i])>r) { c = i;  r = i+p[i]; }
			}
			return p;
		}
		private  char[] addBoundaries(char[] cs) {
			if (cs==null || cs.length==0)
				return new char[] {BOUNDARY_CHARACTER, BOUNDARY_CHARACTER};
			char[] cs2 = new char[cs.length*2+1];
			for (int i = 0; i<(cs2.length-1); i = i+2) {
				cs2[i] = BOUNDARY_CHARACTER;  cs2[i+1] = cs[i/2];
			}
			cs2[cs2.length-1] = BOUNDARY_CHARACTER;
			return cs2;
		}
	}

	class FastScanner {
		public int BS = 1<<16;
		public char NC = (char)0;
		byte[] buf = new byte[BS];
		int bId = 0, size = 0;
		char c = NC;
		double num = 1;
		BufferedInputStream in;

		public FastScanner() {
			in = new BufferedInputStream(System.in, BS);
		}

		public FastScanner(String s) throws FileNotFoundException {
			in = new BufferedInputStream(new FileInputStream(new File(s)), BS);
		}

		public char nextChar(){
			while(bId==size) {
				try {
					size = in.read(buf);
				}catch(Exception e) {
					return NC;
				}                
				if(size==-1)return NC;
				bId=0;
			}
			return (char)buf[bId++];
		}

		public int nextInt() {
			return (int)nextLong();
		}

		public long nextLong() {
			num=1;
			boolean neg = false;
			if(c==NC)c=nextChar();
			for(;(c<'0' || c>'9'); c = nextChar()) {
				if(c=='-')neg=true;
			}
			long res = 0;
			for(; c>='0' && c <='9'; c=nextChar()) {
				res = (res<<3)+(res<<1)+c-'0';
				num*=10;
			}
			return neg?-res:res;
		}

		public double nextDouble() {
			double cur = nextLong();
			return c!='.' ? cur:cur+nextLong()/num;
		}

		public String next() {
			StringBuilder res = new StringBuilder();
			while(c<=32)c=nextChar();
			while(c>32) {
				res.append(c);
				c=nextChar();
			}
			return res.toString();
		}

		public String nextLine() {
			StringBuilder res = new StringBuilder();
			while(c<=32)c=nextChar();
			while(c!='\n') {
				res.append(c);
				c=nextChar();
			}
			return res.toString();
		}

		public boolean hasNext() {
			if(c>32)return true;
			while(true) {
				c=nextChar();
				if(c==NC)return false;
				else if(c>32)return true;
			}
		}

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

	}


}