Problem: Training is indispensable for achieving good results at ICPC. Rabbit wants to win at ICPC, so he decided to practice today as well.

Today's training is to quickly solve popular puzzles and train your instantaneous power. Today's challenge is a puzzle of colorful tiles lined up and erasing them well.

In the initial state, tiles are placed on some squares on the grid. Each tile is colored. After the game starts, the player can perform the operations shown in the following procedure many times.

1. Select one square without tiles and hit that square.
2. Follow from the hit square to the top, and pay attention to the tile when you reach the square where the tile is placed. If you get to the edge of the board without the squares on which the tiles are placed, you will not pay attention to anything.
3. Perform the same operation from the square you hit to the bottom, left, and right. Up to 4 tiles will be the focus of attention.
4. If any of the tiles of interest have the same color, remove those tiles from the board. If there are two pairs of tiles of the same color, remove both.
5. The score will be the same as the number of tiles removed.
6. Stop paying attention.



For example, consider the following situation. The squares without tiles are periods, and the tile colors are represented by uppercase letters.


..A ......
....... B ..
..........
..B ......
..A.CC ....


Now consider the operation of hitting the squares in the second row from the top and the third column from the left. Since there are three tiles of interest, `A`,` B`, and `B`, the two of` B` disappear and the board becomes as follows, and two points are obtained.


..A ......
..........
..........
..........
..A.CC ....


If this puzzle is slow, the time will run out, and you will not be able to see part of the board and you will not know how much training you lacked. Two tiles of each color are placed, but it is not always possible to erase all of them, so let the program calculate the maximum score in advance.



Input


M N
C1,1 C1,2 ... C1, N
C2,1 C2,2 ... C2, N
...
CM, 1CM, 2 ... CM, N


The integers M and N indicate that the board is a grid of vertical M x horizontal N. Ci and j are uppercase letters or periods (`.`), And for the cells in the i-th row from the top and the j-th column from the left, the uppercase letters indicate the color of the tiles placed, and the period indicates the color of the tile. Indicates that no tile is placed on this square.

Satisfy 1 ≤ M ≤ 500 and 1 ≤ N ≤ 500. Each uppercase letter appears as 0 or 2 as you type.

Output

Output the maximum score on one line.

Examples

Input

5 10
..A.......
.......B..
..........
..B.......
..A.CC....


Output

4


Input

3 3
ABC
D.D
CBA


Output

4


Input

5 7
NUTUBOR
QT.SZRQ
SANAGIP
LMDGZBM
KLKIODP


Output

34

Solution (in CPP):

Solution:
                                        #include <bits/stdc++.h>
                                        #include<iostream>
                                        #include<cstdio>
                                        #include<vector>
                                        #include<queue>
                                        #include<map>
                                        #include<cstring>
                                        #include<string>
                                        #include <math.h>
                                        #include<algorithm>
                                    //    #include <boost/multiprecision/cpp_int.hpp>
                                        #include<functional>
                                #define int long long
                                        #define inf  1000000007
                                        #define pa pair<int,int>
                                        #define ll long long
                                        #define pal pair<double,pa>
                                        #define ppa pair<string,int>
                                        #define ppap pair<int,pa>
                                        #define ssa pair<string,int>
                                        #define  mp make_pair
                                        #define  pb push_back
                                        #define EPS (1e-12)
                                        #define equals(a,b) (fabs((a)-(b))<EPS)
                                  #define VI vector<int>
                                        using namespace std;
                                        
                                  class pas{
                                    	public:
                                    	int x,y;
                                    	pas(int x=0,int y=0):x(x),y(y) {}
                                    	pas operator + (pas p) {return pas(x+p.x,y+p.y);}
                                    	pas operator - (pas p) {return pas(x-p.x,y-p.y);}
                                    	pas operator * (int a) {return pas(x*a,y*a);}
                                    	pas operator / (int a) {return pas(x/a,y/a);}
                                    //	double absv() {return sqrt(norm());}
                                    	int norm() {return x*x+y*y;}
                                    	bool operator < (const pas &p) const{
                                   		return x != p.x ? x<p.x: y<p.y;
                                   	}
                                  //		bool operator < (const pas &p) const{
                                    //		return y != p.y ? y<p.y: x<p.x;
                                    //	}
                                    	bool operator == (const pas &p) const{
                                    		return x==p.x && y==p.y;
                                    	}
                                    };

                                        class Point{
                                        	public:
                                        	double x,y;
                                        	Point(double x=0,double y=0):x(x),y(y) {}
                                        	Point operator + (Point p) {return Point(x+p.x,y+p.y);}
                                        	Point operator - (Point p) {return Point(x-p.x,y-p.y);}
                                        	Point operator * (double a) {return Point(x*a,y*a);}
                                        	Point operator / (double a) {return Point(x/a,y/a);}
                                        	double absv() {return sqrt(norm());}
                                        	double norm() {return x*x+y*y;}
                                        	bool operator < (const Point &p) const{
                                        		return x != p.x ? x<p.x: y<p.y;
                                        	}
                                        	bool operator == (const Point &p) const{
                                        		return fabs(x-p.x)<EPS && fabs(y-p.y)<EPS;
                                        	}
                                        };
                                        typedef Point Vector;
                                 #define pl pair<int,pas>
                                        struct Segment{
                                        Point p1,p2;
                                        };
                                        
struct star{
Segment se[5];
};
                                         double dot(Vector a,Vector b){
                                        	return a.x*b.x+a.y*b.y;
                                        }
                                        double cross(Vector a,Vector b){
                                        	return a.x*b.y-a.y*b.x;
                                        }
                                    
            bool parareru(Point a,Point b,Point c,Point d){
            //	if(abs(cross(a-b,d-c))<EPS)cout<<"dd "<<cross(a-b,d-c)<<endl;
            	return abs(cross(a-b,d-c))<EPS;
            }
            double distance_ls_p(Point a, Point b, Point c) {
              if ( dot(b-a, c-a) < EPS ) return (c-a).absv();
              if ( dot(a-b, c-b) < EPS ) return (c-b).absv();
              return abs(cross(b-a, c-a)) / (b-a).absv();
            }
            bool is_intersected_ls(Segment a,Segment b) {
            	if(a.p1==b.p1||a.p2==b.p1||a.p1==b.p2||a.p2==b.p2) return false;
            	if(parareru((a.p2),(a.p1),(b.p1),(b.p2))&&parareru((a.p2),(a.p1),(b.p1),(b.p1))){
            //		cout<<"sss"<<endl;
            		if(dot(a.p1-b.p1,a.p1-b.p2)<EPS) return true;
            		if(dot(a.p2-b.p1,a.p2-b.p2)<EPS) return true;
            		if(dot(a.p1-b.p1,a.p2-b.p1)<EPS) return true;
            		if(dot(a.p1-b.p2,a.p2-b.p2)<EPS) return true;
            		return false;
            	}
              else return ( cross(a.p2-a.p1, b.p1-a.p1) * cross(a.p2-a.p1, b.p2-a.p1) < EPS ) && ( cross(b.p2-b.p1, a.p1-b.p1) * cross(b.p2-b.p1, a.p2-b.p1) < EPS );
            }
            double segment_len(Segment a){
            	
            	return (a.p1-a.p2).absv();
            }
            double segment_dis(Segment a,Segment b){
            	if(is_intersected_ls(a,b))return 0;
            	double r=distance_ls_p(a.p1, a.p2, b.p1);
            	r=min(r,distance_ls_p(a.p1, a.p2, b.p2));
            	r=min(r,distance_ls_p(b.p1, b.p2, a.p2));
            	r=min(r,distance_ls_p(b.p1, b.p2, a.p1));
            	return r;
            }
            Point intersection_ls(Segment a, Segment b) {
              Point ba = b.p2-b.p1;
              double d1 = abs(cross(ba, a.p1-b.p1));
              double d2 = abs(cross(ba, a.p2-b.p1));
              double t = d1 / (d1 + d2);
             
              return a.p1 + (a.p2-a.p1) * t;
            }
			pair<Point,Point> circle_intersection(Point c1,double r1,Point c2,double r2){
				double d=(c1-c2).absv();
				double h=(r1*r1-r2*r2+d*d)/2.0/d;
				double l=sqrt(r1*r1-h*h);
			//	cout<<d<<" "<<h<<" "<<l<<endl;
				Point asi=c1+(c2-c1)*h/((c2-c1).absv());
				Vector r1r2=(c2-c1)/((c2-c1).absv());
				Vector sui={r1r2.y,-r1r2.x};
			//	cout<<sui.x<<" "<<sui.y<<endl;
				pair<Point,Point> z=mp(asi+sui*l,asi-sui*l);
				if(z.first.x>z.second.x) swap(z.first,z.second);
				return z;
			}

int gcd(int x,int y){
	if(x<y) return gcd(y,x);
	if(x==y) return x;
	if(x%y==0) return y;
	return gcd(y,x%y);
}
 class pa2{
                                            public:
                                            int x,y;
                                            pa2(int x=0,int y=0):x(x),y(y) {}
                                            pa2 operator + (pa2 p) {return pa2(x+p.x,y+p.y);}
                                            pa2 operator - (pa2 p) {return pa2(x-p.x,y-p.y);}
                                            bool operator < (const pa2 &p) const{
                                                return x != p.x ? x<p.x: y<p.y;
                                            }
										 	 bool operator > (const pa2 &p) const{
                                                return x != p.x ? x>p.x: y>p.y;
                                            }
                                            bool operator == (const pa2 &p) const{
                                                return abs(x-p.x)==0 && abs(y-p.y)==0;
                                            }
                                            bool operator != (const pa2 &p) const{
                                                return !(abs(x-p.x)==0 && abs(y-p.y)==0);
                                            }
                                                 
                                         
                                        };

/*　　　---memo---
add_edge(始点,終点,youryou ,コスト)で枝追加
min_cost_flow(始点,終点,ryou)でhiyouをintで返す
*/
int a[600][600]={0};
vector<pa> ve[30],ve2[30];

bool ch(pa r1,pa r2){
	if(r1.first==r2.first){
		if(abs(r1.second-r2.second)==1) return false;
		int r3=min(r1.second,r2.second),r4=max(r1.second,r2.second);
		bool bo=true;
		for(int k=r3+1;k<r4;k++)if(a[r1.first][k]>=0) return false;
		
		return true;
	}
	
	if(r1.second==r2.second){
	//	cout<<"e"<<endl;
		if(abs(r1.first-r2.first)==1) return false;
		int r3=min(r1.first,r2.first),r4=max(r1.first,r2.first);
		bool bo=true;
		for(int k=r3+1;k<r4;k++)if(a[k][r1.second]>=0) return false;
		
		return true;
	}
	
	if(r1.second>r2.second) swap(r1,r2);
	if(r2.first>r1.first){
		bool bo=true;
		
		for(int k=r1.second+1;k<=r2.second;k++)if(a[r1.first][k]>=0) bo=false;
		for(int k=r1.first;k<r2.first;k++)if(a[k][r2.second]>=0)bo=false;
		if(bo) return true;
		bo=true;
		
		for(int k=r1.second;k<r2.second;k++)if(a[r2.first][k]>=0) bo=false;
		for(int k=r1.first+1;k<=r2.first;k++)if(a[k][r1.second]>=0)bo=false;
		if(bo) return true;
		return false;
	}
	else{
		bool bo=true;
		
		for(int k=r1.first-1;k>=r2.first;k--)if(a[k][r1.second]>=0) bo=false;
		for(int k=r1.second;k<r2.second;k++)if(a[r2.first][k]>=0)bo=false;
		if(bo) return true;
		bo=true;
		
		for(int k=r1.second+1;k<=r2.second;k++)if(a[r1.first][k]>=0) bo=false;
		for(int k=r2.first+1;k<=r1.first;k++)if(a[k][r2.second]>=0)bo=false;
		if(bo) return true;
		return false;
		
	}
}


     signed main(){
int h,w;
     	cin>>h>>w;
     	for(int i=0;i<600;i++)for(int j=0;j<600;j++)a[i][j]=-1;
     	
     	for(int i=0;i<h;i++){
     		string s;
     		cin>>s;
     		for(int j=0;j<w;j++){
     			if(s[j]=='.') continue;
     			a[i][j]=1;
     			ve[s[j]-'A'].pb(mp(i,j));
     		}
     	}
     	int ans=0;
     //		cout<<"r"<<endl;
     	for(int i=0;i<26;i++){
     		if(ve[i].size()==0) continue;
     		
     		
     		
     		
     	}
     //	cout<<"r"<<endl;
     	for(int cn=0;cn<=100;cn++){
     		for(int i=0;i<26;i++)if(ve[i].size()>0){
     			if(ch(ve[i][0],ve[i][1])){
     			ans++;
     //				cout<<i<<endl;
     				a[ve[i][0].first][ve[i][0].second]=-1;
     				a[ve[i][1].first][ve[i][1].second]=-1;
     				ve[i].clear();
     				
     			//	for(int k=0;k<h;k++){
     			//		for(int l=0;l<w;l++)cout<<a[k][l]<<" ";
     			//		cout<<endl;
     			//	}
     			
     			}
     		
     		
     		}
     	}
     	cout<<2*ans<<endl;

    
           	return 0;
           }