#include <bits/stdc++.h>
using namespace std;
struct Hsh {
  long long mod, base;
  static const int PWC = 300;
  long long pw[2 * PWC];
  int is_good[PWC];
  int good_pfx[PWC];
  long long cnt[PWC];
  long long fwd[PWC], rev[PWC];
  Hsh(int m, int b) {
    mod = m;
    base = b;
    pw[0] = 1;
    cnt[0] = 0;
    for (int i = 1; i < PWC; ++i) {
      pw[i] = pw[i - 1] * base % mod;
      cnt[i] = 0;
    }
  }
  void clear() { memset(cnt, 0, sizeof cnt); }
  void add(int i, long long v) { cnt[i] += v; }
  void assign_good(int i, bool g) { is_good[i] = g; }
  void build() {
    rev[PWC - 1] = 0;
    fwd[0] = 0;
    good_pfx[0] = 0;
    for (int i = 1; i < PWC; ++i) {
      cnt[i] %= mod;
      fwd[i] = (fwd[i - 1] + pw[i] * cnt[i]) % mod;
      good_pfx[i] = good_pfx[i - 1] + is_good[i];
    }
    for (int i = PWC - 2; i >= 0; --i) {
      rev[i] = (rev[i + 1] + pw[PWC - 1 - i] * cnt[i]) % mod;
    }
  }
  bool good_range(int l, int r) {
    return good_pfx[r] - good_pfx[l - 1] == (r - l + 1);
  }
  long long get_fwd(int l, int r) {
    long long va = (mod + fwd[r] - fwd[l - 1]) % mod;
    va = (va * pw[PWC - l]) % mod;
    return va;
  }
  long long get_rev(int l, int r) {
    long long va = (mod + rev[l] - rev[r + 1]) % mod;
    va = (va * pw[PWC - (PWC - 1 - r)]) % mod;
    return va;
  }
};
int ord(char c) { return c - 'a'; }
const int N = 260;
char gr[N][N];
int cnt[N][30];
const long long b1 = 9973, b2 = 9967;
const long long m1 = 998244353, m2 = 1000696969;
long long pw1[30], pw2[30];
bool is_good[N];
long long mhsh1[N];
long long mhsh2[N];
int len[N * 2];
int n, m;
void setup() {
  pw1[0] = pw2[0] = 1;
  for (int i = 1; i < 30; ++i) {
    pw1[i] = pw1[i - 1] * b1 % m1;
    pw2[i] = pw2[i - 1] * b2 % m2;
  }
}
int main() {
  ios_base::sync_with_stdio(0), cin.tie(0);
  setup();
  cin >> n >> m;
  for (int i = 1; i <= n; ++i) {
    cin >> (gr[i] + 1);
  }
  long long ans = 0;
  for (int a = 1; a <= m; ++a) {
    memset(cnt, 0, sizeof cnt);
    memset(mhsh1, 0, sizeof mhsh1);
    memset(mhsh2, 0, sizeof mhsh2);
    for (int b = a; b <= m; ++b) {
      for (int i = 1; i <= n; ++i) {
        constexpr int md1 = 1e9 + 7;
        constexpr int md2 = 1e9 + 9;
        mhsh1[i] = (mhsh1[i] + pw1[ord(gr[i][b])]) % md1;
        mhsh2[i] = (mhsh2[i] + pw2[ord(gr[i][b])]) % md2;
        cnt[i][ord(gr[i][b])]++;
        int oddc = 0;
        for (int j = 0; j < 26; ++j) {
          oddc += cnt[i][j] % 2;
        }
        is_good[i] = oddc <= 1;
      }
      int far = 0, fr = 0, fl = 0;
      for (int i = 1; i <= n; ++i) {
        len[i] = 0;
        if (i <= fr) {
          len[i] = max(0, min(len[fl + (fr - i)], fr - i + 1));
        }
        while (i - len[i] >= 1 && i + len[i] <= n &&
               (mhsh1[i - len[i]] == mhsh1[i + len[i]]) &&
               mhsh2[i - len[i]] == mhsh2[i + len[i]] && is_good[i - len[i]] &&
               is_good[i + len[i]]) {
          ++len[i];
        }
        ans += len[i];
        if (len[i] + i - 1 > fr) {
          fr = len[i] + i - 1;
          fl = i - len[i] + 1;
          assert(fl >= 1);
          far = i;
        }
      }
      far = 0, fr = 0, fl = 0;
      for (int i = 1; i < n; ++i) {
        len[i] = 0;
        if (i + 1 <= fr) {
          len[i] = max(0, min(len[fl + (fr - i - 1)], fr - i));
        }
        while (i - len[i] >= 1 && i + len[i] + 1 <= n &&
               (mhsh1[i - len[i]] == mhsh1[i + len[i] + 1]) &&
               (mhsh2[i - len[i]] == mhsh2[i + len[i] + 1]) &&
               is_good[i - len[i]] && is_good[i + len[i] + 1]) {
          ++len[i];
        }
        ans += len[i];
        if (len[i] + i - 1 > fr) {
          fr = len[i] + i;
          fl = i - len[i] + 1;
          far = i;
        }
      }
    }
  }
  cout << ans << "\n";
  return 0;
}
