#include <bits/stdc++.h>
using namespace std;
#define int long long
#define rep(i, a, b) for (int i = (a); i < ((int)(b)); ++i)
#define rrep(i, a, b) for (int i = (int)(b) - 1; i >= ((int)(a)); --i)
#define all(c) c.begin(), c.end()
#define sz(c) ((int)c.size())
using pii = pair<int, int>;
using vi = vector<int>;
using vvi = vector<vi>;

void dump_impl(string s) {}
template <class H, class... T>
void dump_impl(string s, H head, T... tail) {
    int p = 0;
    rep(i, 0, sz(s)) {
        char x = s[i];
        if (x == ',' && p == 0) {
            cerr << " = " << head << ", ";
            dump_impl(s.substr(i + 1), tail...);
            return;
        } else {
            cerr << x;
            if (x == '(') p++;
            if (x == ')') p--;
        }
    }
}
// #define dump(...) do { cerr << "\x1b[33;1m"; dump_impl(#__VA_ARGS__ ",", __VA_ARGS__); cerr << "\x1b[0m" << endl; } while (0)
#define dump(...)

struct Edge {
    int src;
    int dst;
    int lr;
};

struct Node {
    int deg[2];
    bool check() {
        return deg[0] == 0 || deg[1] == 0;
    }
};

const int INF = 1e9;

signed main() {
    int H, W;
    cin >> H >> W;
    vector<string> S(H);
    rep(i, 0, H) {
        cin >> S[i];
    }
    
    vector<Node> node(26);
    vector<vector<Edge>> g(26);
    
    vector<vector<pii>> pos(26);

    vector<int> vis(26, true);
    rep(r, 0, H) {
        rep(c, 0, W) {
            if (S[r][c] != '.') {
                pos[S[r][c] - 'A'].push_back({r, c});
                vis[S[r][c] - 'A'] = false;
            }
        }
    }

    rep(i, 0, 26) {
        if (sz(pos[i]) == 0) continue;
        assert(sz(pos[i]) == 2);
        int x1, y1, x2, y2;
        tie(y1, x1) = pos[i][0];
        tie(y2, x2) = pos[i][1];
        if ((abs(x1 - x2) == 1 && y1 == y2) || (abs(y1 - y2) == 1 && x1 == x2)) {
            vis[i] = true;
            continue;
        }
        
        if (y1 == y2) {
            set<int> tmp;
            rep(x, min(x1, x2) + 1, max(x1, x2)) {
                if (S[y1][x] != '.') {
                    tmp.insert(S[y1][x] - 'A');
                }
            }
            for (int x : tmp) {
                g[x].push_back(Edge{x, i, 0});
                node[i].deg[0]++;
                node[i].deg[1] = INF;
            }
        } else if (x1 == x2) {
            set<int> tmp;
            rep(y, min(y1, y2) + 1, max(y1, y2)) {
                if (S[y][x1] != '.') {
                    tmp.insert(S[y][x1] - 'A');
                }
            }
            for (int x : tmp) {
                g[x].push_back(Edge{x, i, 0});
                node[i].deg[0]++;
                node[i].deg[1] = INF;
            }
        } else {
            if (x1 < x2) {
                {
                    set<int> tmp;
                    rep(x, x1 + 1, x2 + 1) {
                        if (S[y1][x] != '.') {
                            tmp.insert(S[y1][x] - 'A');
                        }
                    }
                    rep(y, y1, y2) {
                        if (S[y][x2] != '.') {
                            tmp.insert(S[y][x2] - 'A');
                        }
                    }
                    for (int x : tmp) {
                        g[x].push_back(Edge{x, i, 0});
                        node[i].deg[0]++;
                    }
                }
                {
                    set<int> tmp;
                    rep(y, y1 + 1, y2 + 1) {
                        if (S[y][x1] != '.') {
                            tmp.insert(S[y][x1] - 'A');
                        }
                    }
                    rep(x, x1, x2) {
                        if (S[y2][x] != '.') {
                            tmp.insert(S[y2][x] - 'A');
                        }
                    }
                    for (int x : tmp) {
                        g[x].push_back(Edge{x, i, 1});
                        node[i].deg[1]++;
                    }
                }
            } else {
                {
                    set<int> tmp;
                    rrep(x, x2, x1) {
                        if (S[y1][x] != '.') {
                            tmp.insert(S[y1][x] - 'A');
                        }
                    }
                    rep(y, y1, y2) {
                        if (S[y][x2] != '.') {
                            tmp.insert(S[y][x2] - 'A');
                        }
                    }
                    for (int x : tmp) {
                        g[x].push_back(Edge{x, i, 0});
                        node[i].deg[0]++;
                    }
                }
                {
                    set<int> tmp;
                    rep(y, y1 + 1, y2 + 1) {
                        if (S[y][x1] != '.') {
                            tmp.insert(S[y][x1] - 'A');
                        }
                    }
                    rrep(x, x2 + 1, x1 + 1) {
                        if (S[y2][x] != '.') {
                            tmp.insert(S[y2][x] - 'A');
                        }
                    }
                    for (int x : tmp) {
                        g[x].push_back(Edge{x, i, 1});
                        node[i].deg[1]++;
                    }
                }
            }
        }
    }


    dump(vis['T'-'A']);

    int ans = 0;
    queue<int> q;
    rep(i, 0, 26) {
        if (vis[i]) continue;
        dump(char(i+'A'), node[i].deg[0], node[i].deg[1]);
        if (node[i].check()) {
            q.push(i);
            vis[i] = true;
            ans += 2;
            dump(i);
        }
    }
    while (sz(q)) {
        int x = q.front(); q.pop();
        for (Edge e : g[x]) {
            if (vis[e.dst]) continue;

            node[e.dst].deg[e.lr]--;
            if (node[e.dst].check()) {
                vis[e.dst] = true;
                ans += 2;
                q.push(e.dst);
            }
        }
    }
    cout << ans << endl;
}


Measured memory_bytes: 3364