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.
cHJvZ3JhbSBjYXNpbm87ICgqY29uIEFsZ29yaXRtbyBkaSBCb290aCopClVzZXMgc3lzdXRpbHM7CnskSCt9CmNvbnN0IGx1bmc9MTAwMDAwMDsKdHlwZSBlbGVuY289YXJyYXlbMC4ubHVuZy0xXSBvZiBpbnQ2NDsKdmFyICBOLE0sQyx3LHYsdCxjb3BwaWUsaW5kZXg6SW50NjQ7CiAgICAgUyxTX3J1b3RhdGU6YXJyYXlbMC4ubHVuZ10gb2YgQW5zaVN0cmluZzsKICAgICBmdW56X2Vycm9yZTogYXJyYXlbMC4uMjAwMDAwMF0gb2YgSW50NjQ7CiAgICAgSCwgYWNjb3BwaWF0YTplbGVuY287CiAgICAKZnVuY3Rpb24gTGV4aWNhbE1pblJvdGF0aW9uKHZhciB4OiBBbnNpU3RyaW5nKTpJbnQ2NDsKdmFyIApsZW4sSyxpLGo6SW50NjQ7CgpiZWdpbgogICB4Oj14K3g7ICgqY29uY2F0ZW5hcmUgbGEgc3RyaW5nYSBjb24gc2Ugc3Rlc3NhKikKICAgbGVuOj1sZW5ndGgoeCk7IAogICBmb3IgaTo9MCB0byBsZW4gZG8gZnVuel9lcnJvcmVbaV06PS0xOyAoKmluaXppYWxpenphcmUgaWwgdmV0dG9yZSwgZGkgZGltZW5zaW9uZSBkb3BwaWEgZGVsbGEgbHVuZ2hlenphIGRlbGxhIHN0cmluZ2EsY2hpYW1hdG8gZnVuemlvbmVfZXJyb3JlIGEgLTEqKQogICBLOj0xOyAoKmluZGljZSBjaGUgY29ycmlzcG9uZGUgYWwgY2FuZGlkYXRvIGNvcnJlbnRlIGFsbGEgcm90YXppb25lIHBpw7kgcGljY29sYS4gUmljb3JkYXJlIGNoZSBsZSBBbnNpc3RyaW5nIGluaXppYW5vIGRhIDEqKQogICBmb3Igajo9MiB0byBsZW4gZG8gICAoKmNvbmZyb250YSBpbCBjYXJhdHRlcmUgaW4gaiBjb24gaWwgY2FyYXR0ZXJlIGluIEsrZnVuel9lcnJvcmVba10qKQogICAgICAgICAgIGJlZ2luCiAgICAgICAgICAgICBpOj0gZnVuel9lcnJvcmVbai1rLTFdOwogICAgICAgICAgICAgd2hpbGUgKGkgPD4gLTEgKSBhbmQgKHhbal0gPD4geFsoayArIGkrMSApXSkgZG8gICAoKlNlIGMnw6ggdW5hIGRpc2NyZXBhbnphIGFnZ2lvcm5hIGlsIHZhbG9yZSBkaSBrKikKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJlZ2luCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIHhbal0gPCB4WyhrICsgaSsxICldIHRoZW4gazo9IGogLSBpIC0gMTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaTo9ZnVuel9lcnJvcmVbaV07ICAgICAgICAgICAgICAgKCptb2RpZmljYXJlIGxhIGZ1bnppb25lIGVycm9yZSBpbiBiYXNlIGFsIGNvbmZyb250byBlZmZldHR1YXRvICopCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbmQ7ICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgIGlmIChpID0gLTEpIGFuZCAoeFtqXSA8PiB4WyhrICsgaSsxICldKSB0aGVuCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiZWdpbgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgeFtqXSA8IHhbKGsgKyBpKzEgKV0gdGhlbiBrOj0gajsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bnpfZXJyb3JlW2ogLSBrXTo9IC0xOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5kICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2UgICBmdW56X2Vycm9yZVtqIC0ga106PSBpICsgMTsKICAgICAgICAgICAgICAgCiAgICAgICAgIGVuZDsgICAKIExleGljYWxNaW5Sb3RhdGlvbjo9azsgKCpkb3BvIGF2ZXIgY29tcGxldGF0byBpbCBwcm9jZXNzbyBrIGluZGljYSBpbmRpY2UgZGVsbGEgcm90YXppb25lIG1pbmltYSopCiAgICAgCmVuZDsKCmZ1bmN0aW9uIFJhYmluICh2YXIgeDogQW5zaXN0cmluZykgOmludDY0Owp2YXIgbGVuLCBpLGosIFIsaCxkLCBxOmludDY0OwpiZWdpbgogICBoOj0xOyBSOj0wOyBsZW46PWxlbmd0aCh4KTsgcTo9TWF4SW50OyBkOj0yNTY7CiAgIGZvciBpIDo9IDEgIHRvIGxlbiBkbyAgaCA6PSAoaCAqIGQpIG1vZCBxOwogICBmb3IgaSA6PSAxIHRvIGxlbiBkbyAgUjo9IChkICogUiArIG9yZCh4W2ldKSkgbW9kIHE7CiAgIFJhYmluOj0gUjsgCmVuZDsgCgpQcm9jZWR1cmUgc2NhbWJpYSAodmFyIGEsYjogaW50NjQpOwp2YXIgeDppbnQ2NDsKYmVnaW4KICAgeDo9YTsKICAgYTo9YjsKICAgYjo9eDsKZW5kOyAgClByb2NlZHVyZSBvcmRpbmFtZW50byAoZXN0cmVtb2ksZXN0cmVtb3M6IGludDY0OyB2YXIgdiA6IGVsZW5jbzsgb3JkaW5hdG86Ym9vbGVhbik7CnZhciBpbmYsIHN1cCwgbWVkaW86aW50NjQ7CiAgICBwaXZvdCA6aW50NjQ7CmJlZ2luCiAgICBpbmY6PWVzdHJlbW9pOwogICAgc3VwOj1lc3RyZW1vczsKICAgIG1lZGlvOj0gKGVzdHJlbW9pK2VzdHJlbW9zKSBkaXYgMjsKICAgIHBpdm90Oj12W21lZGlvXTsKICAgIHJlcGVhdAogICAgICBpZiAob3JkaW5hdG8pIHRoZW4KICAgICAgICAgYmVnaW4KICAgICAgICAgICAgd2hpbGUgKHZbaW5mXTxwaXZvdCkgZG8gIGluZjo9aW5mKzE7CiAgICAgICAgICAgIHdoaWxlICh2W3N1cF0+cGl2b3QpIGRvICBzdXA6PXN1cC0xOwogICAgICAgICBlbmQ7CiAgICAgIGlmIGluZjw9c3VwIHRoZW4KICAgICAgIGJlZ2luCiAgICAgICAgIHNjYW1iaWEodltpbmZdLHZbc3VwXSk7CiAgICAgICAgIGluZjo9aW5mKzE7CiAgICAgICAgIHN1cDo9c3VwLTE7CiAgICAgICBlbmQ7CiAgICB1bnRpbCBpbmY+c3VwOwogICAgaWYgKGVzdHJlbW9pPHN1cCkgdGhlbiBvcmRpbmFtZW50byhlc3RyZW1vaSxzdXAsdixvcmRpbmF0byk7CiAgICBpZiAoaW5mPGVzdHJlbW9zKSB0aGVuIG9yZGluYW1lbnRvKGluZixlc3RyZW1vcyx2LG9yZGluYXRvKTsKZW5kOyAgICAKCmJlZ2luCiAgICgqYXNzaWduKGlucHV0LCAnaW5wdXQudHh0Jyk7IHJlc2V0KGlucHV0KTsKICAgYXNzaWduKG91dHB1dCwgJ291dHB1dC50eHQnKTsgcmV3cml0ZShvdXRwdXQpOyopCiAgIHJlYWRsbiAoTixNKTsKICAgZm9yIHc6PTAgdG8gTi0xIGRvIGJlZ2luIHJlYWRsbihTW3ddKTsgIFNbd106PVRyaW0oU1t3XSk7IEhbd106PTA7ICBhY2NvcHBpYXRhW3ddOj0wO2VuZDsKICAgY29wcGllOj0wOyAgCiAgZm9yIHc6PTAgdG8gTi0xIGRvCiAgICAgICAgICBiZWdpbgogICAgICAgICAgICBpbmRleDo9TGV4aWNhbE1pblJvdGF0aW9uKFNbd10pOwogICAgICAgICAgICBTX3J1b3RhdGVbd106PWNvcHkoU1t3XSxpbmRleCxNKTsKICAgICAgICAgICAgSFt3XTo9UmFiaW4oU19ydW90YXRlW3ddKTsKICAgICAgICAgIGVuZDsKICAgb3JkaW5hbWVudG8oMCxOLTEsSCx0cnVlKTsgICAgICAKICBmb3Igdzo9MCB0byBOLTEgZG8gIAogICAgICAgICAgICAgICAgICBiZWdpbgogICAgICAgICAgICAgICAgICAgIHQ6PTA7CiAgICAgICAgICAgICAgICAgICAgaWYgSFt3XT1IW3crMV0gdGhlbiAgYWNjb3BwaWF0YVt0XTo9YWNjb3BwaWF0YVt0XSsxCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB0Oj10KzE7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgZW5kOwogICAgICAgICAgICAgICAgICAKICAgIGZvciB3Oj0wIHRvIHQtMSBkbyAKICAgICAgICAgICAgICAgYmVnaW4KICAgICAgICAgICAgICAgICBpZiBhY2NvcHBpYXRhW3ddID0xIHRoZW4gY29wcGllOj1jb3BwaWUrMQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlIGlmIGFjY29wcGlhdGFbd10+MSB0aGVuIGNvcHBpZTo9Y29wcGllKygoYWNjb3BwaWF0YVt3XSsxKSooYWNjb3BwaWF0YVt3XSkgZGl2IDIpOwogICAgICAgICAgICAgICBlbmQ7CiAgICB3cml0ZWxuIChjb3BwaWUpOwplbmQu