#include <bits/stdc++.h>
using namespace std;
class ManacherPalindrome {
 public:
  ManacherPalindrome(const vector<long long>& aS, long long aDammy = 0) {
    dammy = aDammy;
    while (find(begin(aS), end(aS), dammy) != aS.end()) {
      dammy++;
    }
    S.clear();
    for (long long i = 0; i < aS.size(); i++) {
      S.emplace_back(aS[i]);
      if (i < aS.size() - 1) S.emplace_back(dammy);
    }
    R.resize(S.size());
    long long i = 0, j = 0;
    while (i < S.size()) {
      while (i - j >= 0 && i + j < S.size() && S[i - j] == S[i + j]) ++j;
      R[i] = j;
      long long k = 1;
      while (i - k >= 0 && i + k < S.size() && k + R[i - k] < j)
        R[i + k] = R[i - k], ++k;
      i += k;
      j -= k;
    }
  }
  long long getOddR(long long i) {
    assert(0 <= i * 2 && i * 2 < R.size());
    return (R[i * 2] + 1) / 2;
  }
  long long getEvenR(long long i) {
    assert(0 <= i * 2 && i < R.size() / 2);
    return R[i * 2 + 1] / 2;
  }

 private:
  vector<long long> S;
  long long dammy;
  bool oddFlag;
  vector<long long> R;
};
const long long MAX_N = 255;
const long long MAX_M = 255;
long long N, M;
string S[MAX_N];
long long SSBit[MAX_N][MAX_M];
unsigned long long Hash[MAX_N][MAX_M];
unsigned long long table[30];
unsigned long long rollA = 100000007;
unsigned long long rollB = 1000000009;
bool check(long long x) { return __builtin_popcount(x) <= 1; }
unsigned long xor128(void) {
  static unsigned long x = 123456789, y = 362436069, z = 521288629,
                       w = 88675123;
  unsigned long t;
  t = (x ^ (x << 11));
  x = y;
  y = z;
  z = w;
  return (w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)));
}
signed main() {
  for (long long n = (0); n < (30); ++n) {
    table[n] = xor128() % rollB;
  }
  cin >> N >> M;
  for (long long n = (0); n < (N); ++n) {
    cin >> S[n];
    for (long long m = (0); m < (M); ++m) {
      SSBit[n][m + 1] = SSBit[n][m] ^ (1 << (S[n][m] - 'a'));
      Hash[n][m + 1] = (Hash[n][m] + table[S[n][m] - 'a' + 1]) % rollB;
    }
  }
  long long ans = 0;
  for (long long l = (0); l < (M); ++l)
    for (long long r = (l + 1); r < (M + 1); ++r) {
      vector<long long> vec;
      for (long long n = (0); n < (N); ++n) {
        long long b = SSBit[n][r] ^ SSBit[n][l];
        if (check(b)) {
          vec.push_back((Hash[n][r] + rollB - Hash[n][l]) % rollB);
        } else {
          if (vec.size() > 0) {
            ManacherPalindrome pal(vec, -1);
            for (long long n = (0); n < (vec.size()); ++n) {
              ans += pal.getOddR(n);
              if (n < vec.size() - 1) {
                ans += pal.getEvenR(n);
              }
            }
            vec.clear();
          }
        }
      }
      if (vec.size() > 0) {
        ManacherPalindrome pal(vec, -1);
        for (long long n = (0); n < (vec.size()); ++n) {
          ans += pal.getOddR(n);
          if (n < vec.size() - 1) {
            ans += pal.getEvenR(n);
          }
        }
      }
    }
  cout << ans << endl;
  return 0;
}
