using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Numerics;
using System.Threading.Tasks;
using static System.Console;
using static System.Math;
using static Func;
class Z { static void Main() => new K(); }
class K
{
	int F => int.Parse(Str);
	long FL => long.Parse(Str);
	int[] G => Strs.Select(int.Parse).ToArray();
	uint[] GU => Strs.Select(uint.Parse).ToArray();
	decimal[] GD => Strs.Select(decimal.Parse).ToArray();
	long[] GL => Strs.Select(long.Parse).ToArray();
	string Str => ReadLine();
	string[] Strs => Str.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
	static ulong One(int k) => 1ul << k;
	static ulong All(int k) => One(k) - 1;
	static bool Has(ulong s, int k) => (s & One(k)) != 0;
	const int MOD = 1000000007;
	public K()
	{
		SetOut(new StreamWriter(OpenStandardOutput()) { AutoFlush = false });
		Solve();
		Out.Flush();
	}
	void Solve()
	{
		var N = F;
		var d = new Dictionary<long, int>();
		for (var i = 0; i < N; i++)
		{
			var k = ToLong(Str);
			if (!d.ContainsKey(k)) d[k] = 1;
			else d[k]++;
		}
		var s = 0L;
		foreach (var t in d) s += t.Value * (t.Value - 1L) / 2;
		WriteLine(s);
	}
	long ToLong(string S)
	{
		var cs = S.ToCharArray();
		Array.Sort(cs);
		var s = 0L;
		foreach (var c in cs) s = 26 * s + (int)c;
		return s;
	}
}
struct Data : IComparable<Data>
{
	public readonly int Delay, Bonus;
	public Data(int a, int b) { Delay = a; Bonus = b; }
	public int CompareTo(Data other) => other.Bonus.CompareTo(Bonus);
}
static class Func
{
	public const int Inf = 1073741789;
	public const long InfL = 4011686018427387913L;
	public static T[] ConstantArray<T>(int n, T val) { var a = new T[n]; for (var i = 0; i < n; i++) a[i] = val; return a; }
	public static T[] MakeArray<T>(int n, Func<int, T> f) { var a = new T[n]; for (var i = 0; i < n; i++) a[i] = f(i); return a; }
	public static T[] Recurse<T>(int n, T a0, Func<int, T, T> f) { var a = new T[n]; a[0] = a0; for (var i = 1; i < n; i++) a[i] = f(i, a[i - 1]); return a; }
	public static T[] Accumulate<T>(IList<T> a, T zero, Func<T, T, T> f) { var s = new T[a.Count + 1]; s[0] = zero; for (var i = 0; i < a.Count; i++) s[i + 1] = f(s[i], a[i]); return s; }
	public static int FirstBinary(int min, int max, Predicate<int> pred)
	{
		while (min < max)
		{
			var mid = (min + max) / 2;
			if (pred(mid)) max = mid;
			else min = mid + 1;
		}
		return min;
	}
	public static long GCD(long a, long b)
	{
		var n = (ulong)Abs(a); var m = (ulong)Abs(b);
		if (n == 0) return (long)m; if (m == 0) return (long)n;
		int zm = 0, zn = 0;
		while ((n & 1) == 0) { n >>= 1; zn++; }
		while ((m & 1) == 0) { m >>= 1; zm++; }
		while (m != n)
		{
			if (m > n) { m -= n; while ((m & 1) == 0) m >>= 1; }
			else { n -= m; while ((n & 1) == 0) n >>= 1; }
		}
		return (long)n << Min(zm, zn);
	}
	public static long Mod(long a, long mod) => (a % mod + mod) % mod;
	public static long Inverse(long a, long mod) => Mod(SolveLinear(Mod(a, mod), mod)[0], mod);
	public static long Pow(long a, long b, long mod)
	{
		var p = 1L;
		var x = a;
		while (b > 0)
		{
			if ((b & 1) == 1) p = (p * x) % mod;
			b >>= 1;
			x = (x * x) % mod;
		}
		return p;
	}
	public static long[] SolveLinear(long n, long m)
	{
		var A = new long[,] { { n < 0 ? -1 : 1, 0 }, { 0, m < 0 ? -1 : 1 } };
		n = Abs(n); m = Abs(m);
		while (m > 0)
		{
			long q = n / m, r = n % m;
			n = m; m = r;
			for (var i = 0; i < 2; i++)
			{
				var x = A[i, 1];
				A[i, 1] = A[i, 0] - q * x;
				A[i, 0] = x;
			}
		}
		return new long[] { A[0, 0], A[1, 0] };
	}
	public static int CombineHashCodes(int h1, int h2) => (((h1 << 5) + h1) ^ h2);
	public static int[] GetFact(int lim, int mod)
	{
		var f = new int[lim];
		f[0] = 1;
		for (var i = 1; i < lim; i++) f[i] = (int)((long)f[i - 1] * i % mod);
		return f;
	}
	public static int[] GetInvFact(int lim, int mod)
	{
		var fc = 1;
		for (var i = 2; i < lim; i++) fc = (int)((long)fc * i % mod);
		return GetInvFact(lim, fc, mod);
	}
	// GetInvFact(n, (n-1)! mod p, p) gives {1, 1/2, ..., 1/(n-1)!} mod p
	public static int[] GetInvFact(int lim, int fc_of_lim_m_1, int mod)
	{
		var ifc = new int[lim];
		ifc[lim - 1] = (int)Inverse(fc_of_lim_m_1, mod);
		for (var i = lim - 1; i >= 1; i--) ifc[i - 1] = (int)((long)ifc[i] * i % mod);
		return ifc;
	}
}


Measured memory_bytes: 22364