using System;
using System.Collections.Generic;
using static System.Console;
using System.Linq;


class Program
{
    public static double Jacc(HashSet<int> A,HashSet<int> B) {
        HashSet<int> tmp = new HashSet<int>();
        foreach (int e in A) tmp.Add(e);
        foreach (int e in B) tmp.Add(e);

        double OR_len = tmp.Count();
        double AND_len = A.Count() + B.Count() - OR_len;

        return AND_len / OR_len;
    }

    static void Main(string[] Args) {

        long N;
        N = int.Parse(Console.ReadLine());

        int[] primes = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101 };
        string al = "abcdefghijklmnopqrstuvwxyz";

        string tmp;
        decimal ntmp;
        List<decimal> data = new List<decimal>();
        for(long i = 0;i < N;i++) {
            tmp = Console.ReadLine();

            ntmp = 1;
            foreach(char x in tmp) {
                ntmp *= primes[al.IndexOf(x)];
            }

            data.Add(ntmp);
        }

        var gd = data.GroupBy(i => i);
        long ans = 0;
        foreach(var x in gd) {
            ans += C(x.Count(), 2);
        }

        Console.WriteLine(ans);

        Console.ReadLine();
    }


    static int getmin(int x,int y) {
        return (x < y) ? y : x;
    }
    static int getmax(int x,int y) {
        return (x < y) ? x : y;
    }

    class MyList<T> : List<T>
    {
        public override bool Equals(object obj) {
            List<T> obj_ = (List<T>)obj;
            if (this.Count != obj_.Count) return false;
            for (int i = 0; i < this.Count(); i++) {
                if (!this[i].Equals(obj_[i])) {
                    //WriteLine(this[i].Equals(obj_[i]));
                    //WriteLine(string.Format("this[{0}] = {1},obj_[{0}] = {2}", i, this[i], obj_[i]));
                    return false;
                }
            }
            return true;
        }
        public override int GetHashCode() {
            return base.GetHashCode();
        }
        //public static implicit operator MyList<T> (List<T> obj) {
        public static MyList<T> conv(List<T> obj) {
            MyList<T> res = new MyList<T>();
            foreach (T e in obj) res.Add(e);
            return res;
        }
        public MyList<T> Copy() {
            MyList<T> res = new MyList<T>();
            foreach(T e in this)
                res.Add(e);
            return res;
        }
    }

    static MyList<MyList<int>> GetIndex(MyList<Tuple<int,char,int>> Dict,int Count) {
        if(Count == 0) {
            MyList<MyList<int>> res = new MyList<MyList<int>>();
            MyList<int> res_ = new MyList<int>();
            res_.Add(-1);
            res.Add(res_);
            return res;
        }
        MyList<MyList<int>> res_indexes = new MyList<MyList<int>>();
        for(int i = 0;i < Dict.Count(); i++) {
            MyList<Tuple<int,char,int>> clone = Dict.Copy();
            clone.RemoveAt(i);
            MyList<MyList<int>> res = GetIndex(clone, Count - 1);
            MyList<int> temporary = new MyList<int>();
            foreach(MyList<int> ele in res) {
                temporary = new MyList<int>();
                temporary.Add(Dict[i].Item1);
                foreach(int ele_s_ele in ele) {
                    temporary.Add(ele_s_ele);
                }
                temporary.Sort();
                if(!res_indexes.Contains(temporary))
                    res_indexes.Add(temporary);
            }
        }
        
        //res_indexes = MyList<MyList<int>>.conv(res_indexes.Distinct().ToList());

        for (int i = 0; i < res_indexes.Count; i++)
            res_indexes[i].Remove(-1);
                
        return res_indexes;
    }

    static int div2(Dictionary<char,int> Dict,char without,int count) {
        if (count == 0) return 1;
        Dictionary<char, int> Dict_Copyed;
        Clone(Dict,out Dict_Copyed);
        Dict_Copyed.Remove(without);
        //foreach(var e in Dict_Copyed) 
        //    WriteLine(e.Key + ":" + e.Value + " ");
        //line();
        int result = 0;
        foreach(var e in Dict_Copyed) {
            result += div2(Dict_Copyed, e.Key, count - 1) * e.Value;
        }
        return result;
    }

    static void line() { WriteLine(); }

    static int kaizyo(int x) {
        int res = 1;
        for (int i = 1; i <= x; i++) res *= i;
        return res;
    }

    static void Clone(Dictionary<char,int> ori,out Dictionary<char,int> tar) {
        tar = new Dictionary<char, int>();
        foreach (KeyValuePair<char,int> e in ori)
            tar.Add(e.Key,e.Value);
    }

    static int div(Dictionary<char, int> _Dict,char without,int count) {
        if (count == 0) return 1;
        Dictionary<char, int> Dict = new Dictionary<char, int>();
        foreach (KeyValuePair<char,int> c in _Dict)
            Dict.Add(c.Key,c.Value);
        Dict.Remove(without);
        int Result = 0;
        foreach (KeyValuePair<char, int> c in Dict) {
            Result += div(Dict, c.Key, count - 1) * c.Value;
        }
        return Result;
    }

    static long C(long x,long y) {
        long Result = 1;
        for(int count = 0;count < y; count++)
            Result *= (x - count);
        for (int count = 0;count < y; count++)
            Result /= (y - count);
        return Result;
    }
}


Measured memory_bytes: 33120