#include<bits/stdc++.h>
using namespace std;
using ll = long long;

// #undef DEBUG
// #define DEBUG
// DEBUG {{{
// clang-format off
template<int n, class...T> typename enable_if<(n>=sizeof...(T))>::type _ot(ostream &, tuple<T...> const &){}
template<int n, class...T> typename enable_if<(n< sizeof...(T))>::type _ot(ostream & os, tuple<T...> const & t){ os << (n==0?"":", ") << get<n>(t); _ot<n+1>(os, t); }
template<class...T> ostream & operator<<(ostream &o, tuple<T...> const &t){ o << "("; _ot<0>(o, t); o << ")"; return o; }
template<class T, class U> ostream & operator<<(ostream &o, pair<T, U> const &p) { o << "(" << p.first << ", " << p.second << ")"; return o; }
#ifdef DEBUG
#if !defined(DEBUG_OUT)
// #define DEBUG_OUT cerr
#endif
#define dump(...) [&](){auto __debug_tap=make_tuple(__VA_ARGS__);DEBUG_OUT<<"["<<__LINE__<< "] "<<#__VA_ARGS__<<" = "<<__debug_tap<<"\n";}()
template < class T > inline void dump2D(T &d, size_t sizey, size_t sizex) { for(size_t i = 0; i < sizey; i++) { DEBUG_OUT << "\t"; for(size_t j = 0; j < sizex; j++) DEBUG_OUT << d[i][j] << (j + 1 == sizex ? "" : "\t"); DEBUG_OUT << endl; } }
template < class T, class = typename iterator_traits< typename T::iterator >::value_type, class = typename enable_if<!is_same<T, string>::value>::type > ostream &operator<<(ostream &o, const T &a) { o << "{"; for(auto ite = a.begin(); ite != a.end(); ++ite) o << (ite == a.begin() ? "" : ", ") << *ite; o << "}"; return o; }
#else
#define dump(...) (42)
#define dump2D(...) (42)
template < class T, class = typename iterator_traits< typename T::iterator >::value_type, class = typename enable_if<!is_same<T, string>::value>::type > ostream &operator<<(ostream &o, const T &a) { for(auto ite = a.begin(); ite != a.end(); ++ite) o << (ite == a.begin() ? "" : " ") << *ite; return o; }
#endif
// clang-format on
// }}}

string s[300];
// [y][x][t] := tずらしたらs[y][x]は右s[y][x+1]と一致するか
// をyで累積
int cnt[301][301][300+301][2];
int h, w;

// [y1, y2]
int range(int y1, int y2, int x, int t, int L) {
  int res = cnt[y2][x][300+t][L];
  if(y1-1>=0) res -= cnt[y1-1][x][300+t][L];
  return res;
}

int dp[301][301];

int main() {
  std::ios::sync_with_stdio(false), std::cin.tie(0);
  cin >> h >> w;
  for(int i = 0; i < h; i++) cin >> s[i];
  //
  for(int i = 0; i < h; i++) for(int j = 0; j < w - 1; j++) for(int t = -h+1; t < h; t++)
    if(i+t>=0 && i + t < h && s[i][j] == s[i + t][j + 1]) cnt[i][j][300+t][0] = 1;
  for(int i = 1; i < h; i++) for(int j = 0; j < w - 1; j++) for(int t = -h+1; t < h; t++)
    cnt[i][j][300 + t][0] += cnt[i-1][j][300 + t][0];

  for(int i = 0; i < h; i++) for(int j = 1; j < w; j++) for(int t = -h+1; t < h; t++)
    if(i+t >= 0 && i + t < h && s[i][j] == s[i + t][j - 1]) cnt[i][j][300+t][1] = 1;
  for(int i = 1; i < h; i++) for(int j = 1; j < w; j++) for(int t = -h+1; t < h; t++)
    cnt[i][j][300 + t][1] += cnt[i-1][j][300 + t][1];
  //
  ll ans = 0;
  for(int x = 0; x < w - 1; x++) {
    // dump(x);
    dp[0][0] = 0;
    for(int a = 0; a <= h; a++) {
      for(int b = 0; b <= h; b++) {
        if(a==0 && b == 0) continue;
        dp[a][b] = 1e9;
        if(a-1>=0) {
          dp[a][b] = min(dp[a][b], dp[a-1][b] + range(0, h-1-(a-1), x, a-1-b,0));
        }
        if(b-1>=0) {
          dp[a][b] = min(dp[a][b], dp[a][b-1] + range(0, h-1-(b-1), x+1, b-1-a,1));
        }
        // dump(a, b, dp[a][b]);
      }
    }
    // dump(x, dp[h][h]);
    ans += dp[h][h];
  }
  cout << ans << endl;
  return 0;
}



Measured memory_bytes: 424704