program casino; (*con Algoritmo di Booth*)
Uses sysutils;
{$H+}
const lung=1000000;
type elenco=array[0..lung-1] of int64;
var  N,M,C,w,v,t,coppie,index:Int64;
     S,S_ruotate:array[0..lung] of AnsiString;
     funz_errore: array[0..2000000] of Int64;
     H, accoppiata:elenco;
    
function LexicalMinRotation(var x: AnsiString):Int64;
var 
len,K,i,j:Int64;

begin
   x:=x+x; (*concatenare la stringa con se stessa*)
   len:=length(x); 
   for i:=0 to len do funz_errore[i]:=-1; (*inizializzare il vettore, di dimensione doppia della lunghezza della stringa,chiamato funzione_errore a -1*)
   K:=1; (*indice che corrisponde al candidato corrente alla rotazione più piccola. Ricordare che le Ansistring iniziano da 1*)
   for j:=2 to len do   (*confronta il carattere in j con il carattere in K+funz_errore[k]*)
           begin
             i:= funz_errore[j-k-1];
             while (i <> -1 ) and (x[j] <> x[(k + i+1 )]) do   (*Se c'è una discrepanza aggiorna il valore di k*)
                            begin
                              if x[j] < x[(k + i+1 )] then k:= j - i - 1;
                              i:=funz_errore[i];               (*modificare la funzione errore in base al confronto effettuato *)
                            end;                           
            if (i = -1) and (x[j] <> x[(k + i+1 )]) then
                                                       begin
                                                          if x[j] < x[(k + i+1 )] then k:= j;
                                                          funz_errore[j - k]:= -1;
                                                       end           
                                                    else   funz_errore[j - k]:= i + 1;
               
         end;   
 LexicalMinRotation:=k; (*dopo aver completato il processo k indica indice della rotazione minima*)
     
end;

function Rabin (var x: Ansistring) :int64;
var len, i,j, R,h,d, q:int64;
begin
   h:=1; R:=0; len:=length(x); q:=MaxInt; d:=256;
   for i := 1  to len do  h := (h * d) mod q;
   for i := 1 to len do  R:= (d * R + ord(x[i])) mod q;
   Rabin:= R; 
end; 

Procedure scambia (var a,b: int64);
var x:int64;
begin
   x:=a;
   a:=b;
   b:=x;
end;  
Procedure ordinamento (estremoi,estremos: int64; var v : elenco; ordinato:boolean);
var inf, sup, medio:int64;
    pivot :int64;
begin
    inf:=estremoi;
    sup:=estremos;
    medio:= (estremoi+estremos) div 2;
    pivot:=v[medio];
    repeat
      if (ordinato) then
         begin
            while (v[inf]<pivot) do  inf:=inf+1;
            while (v[sup]>pivot) do  sup:=sup-1;
         end;
      if inf<=sup then
       begin
         scambia(v[inf],v[sup]);
         inf:=inf+1;
         sup:=sup-1;
       end;
    until inf>sup;
    if (estremoi<sup) then ordinamento(estremoi,sup,v,ordinato);
    if (inf<estremos) then ordinamento(inf,estremos,v,ordinato);
end;    

begin
   (*assign(input, 'input.txt'); reset(input);
   assign(output, 'output.txt'); rewrite(output);*)
   readln (N,M);
   for w:=0 to N-1 do begin readln(S[w]);  S[w]:=Trim(S[w]); H[w]:=0;  accoppiata[w]:=0;end;
   coppie:=0;  
  for w:=0 to N-1 do
          begin
            index:=LexicalMinRotation(S[w]);
            S_ruotate[w]:=copy(S[w],index,M);
            H[w]:=Rabin(S_ruotate[w]);
          end;
   ordinamento(0,N-1,H,true);      
  for w:=0 to N-1 do  
                  begin
                    t:=0;
                    if H[w]=H[w+1] then  accoppiata[t]:=accoppiata[t]+1
                                   else t:=t+1;
                                         
                 end;
                  
    for w:=0 to t-1 do 
               begin
                 if accoppiata[w] =1 then coppie:=coppie+1
                                          else if accoppiata[w]>1 then coppie:=coppie+((accoppiata[w]+1)*(accoppiata[w]) div 2);
               end;
    writeln (coppie);
end.