import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Scanner;

import javax.swing.tree.TreeNode;
class Main{


	static final int MOD = 1000000007;

	static int MAX = 10000000;
	static	ArrayList<TreeNode> tree;
	static HashSet<Integer> set;
	static int[] ans;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);			//文字の入力
		int n = sc.nextInt();
		
		HashMap<String,Integer> map = new HashMap<>();
		long ans = 0;

		for(int i = 0;i < n;i++){
			char[] cc = sc.next().toCharArray();
			Arrays.sort(cc);
			String s = new String(cc);
			int num = map.getOrDefault(s, 0);
			map.put(s, num+1);
			if(num >= 1){
				ans += num;
			}
		}
//		COMinit();  					//二項定理デーブル作成
		
//		for(int num:map.values()){
//			ans += COM(num, 2);
//
//		}
		System.out.println(ans);
		
		
		
	}

	static long fac[] = new long[MAX];
	static long finv[] = new long[MAX];
	static long inv[] = new long[MAX];

	

//テーブルの作成
	static void COMinit() {
		fac[0] = fac[1] = 1;
		finv[0] = finv[1] = 1;
		inv[1] = 1;
		for (int i = 2; i < MAX; i++){
			fac[i] = fac[i - 1] * i % MOD;
			inv[i] = MOD - inv[MOD%i] * (MOD / i) % MOD;
			finv[i] = finv[i - 1] * inv[i] % MOD;
		}
	}

	// 二項係数計算
	static	long COM(int n, int k){
		if (n < k) return 0;
		if (n < 0 || k < 0) return 0;
		return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
	}








	static int upperbond(int k,ArrayList<Integer> data){		//k以下で最大の値をdataの中から探し、返す二分探索
		if(data == null){
			return -1;
		}
		int max = data.size();
		int min = -1;
		while(max-min > 1){
			int mid = (max+min)/2;
			if(data.get(mid) <= k){
				min = mid;
			}else{
				max = mid;
			}
		}

		
//		if(min != -1){
//			min = data.get(min);
//		}
		
//		System.out.println(max);
		return min;					//indexを返している
	}

	static int lowerbond(int k,ArrayList<Integer> data){		//k以上で最小の値をdataの中から探し、返す二分探索
		if(data == null){
			return -1;
		}
//		System.out.println("lo");
//		System.out.println("lo");
		int max = data.size();
		int min = -1;

		while(max-min > 1){
			int mid = (max+min)/2;
			if(data.get(mid) >= k){
				max = mid;
			}else{
				min = mid;
			}
		}

		return max;			//indexを返している
	}



	static int gcd(int a,int b){				//最大公約数を返す
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	}
	static long gcd(long a,long b){
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	}



	static long lcm (long a, long b) {
		long g = gcd(a,b);
		return a/g*b;
	}




}

class Pair implements Comparable{
	int from;
	int end;
	public Pair(int from,int end) {
		this.from = from;
		this.end = end;
		// TODO 自動生成されたコンストラクター・スタブ
	}

	@Override
	public int compareTo(Object other) {
		Pair otherpair = (Pair)other;

		return  from - otherpair.from;
	}








}



 import java.util.ArrayList; ArrayList java.util import java.util.Arrays; Arrays java.util import java.util.HashMap; HashMap java.util import java.util.HashSet; HashSet java.util import java.util.Scanner; Scanner java.util import javax.swing.tree.TreeNode; TreeNode javax.swing.tree class Main{


	static final int MOD = 1000000007;

	static int MAX = 10000000;
	static	ArrayList<TreeNode> tree;
	static HashSet<Integer> set;
	static int[] ans;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);			//文字の入力
		int n = sc.nextInt();
		
		HashMap<String,Integer> map = new HashMap<>();
		long ans = 0;

		for(int i = 0;i < n;i++){
			char[] cc = sc.next().toCharArray();
			Arrays.sort(cc);
			String s = new String(cc);
			int num = map.getOrDefault(s, 0);
			map.put(s, num+1);
			if(num >= 1){
				ans += num;
			}
		}
//		COMinit();  					//二項定理デーブル作成
		
//		for(int num:map.values()){
//			ans += COM(num, 2);
//
//		}
		System.out.println(ans);
		
		
		
	}

	static long fac[] = new long[MAX];
	static long finv[] = new long[MAX];
	static long inv[] = new long[MAX];

	

//テーブルの作成
	static void COMinit() {
		fac[0] = fac[1] = 1;
		finv[0] = finv[1] = 1;
		inv[1] = 1;
		for (int i = 2; i < MAX; i++){
			fac[i] = fac[i - 1] * i % MOD;
			inv[i] = MOD - inv[MOD%i] * (MOD / i) % MOD;
			finv[i] = finv[i - 1] * inv[i] % MOD;
		}
	}

	// 二項係数計算
	static	long COM(int n, int k){
		if (n < k) return 0;
		if (n < 0 || k < 0) return 0;
		return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
	}








	static int upperbond(int k,ArrayList<Integer> data){		//k以下で最大の値をdataの中から探し、返す二分探索
		if(data == null){
			return -1;
		}
		int max = data.size();
		int min = -1;
		while(max-min > 1){
			int mid = (max+min)/2;
			if(data.get(mid) <= k){
				min = mid;
			}else{
				max = mid;
			}
		}

		
//		if(min != -1){
//			min = data.get(min);
//		}
		
//		System.out.println(max);
		return min;					//indexを返している
	}

	static int lowerbond(int k,ArrayList<Integer> data){		//k以上で最小の値をdataの中から探し、返す二分探索
		if(data == null){
			return -1;
		}
//		System.out.println("lo");
//		System.out.println("lo");
		int max = data.size();
		int min = -1;

		while(max-min > 1){
			int mid = (max+min)/2;
			if(data.get(mid) >= k){
				max = mid;
			}else{
				min = mid;
			}
		}

		return max;			//indexを返している
	}



	static int gcd(int a,int b){				//最大公約数を返す
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	}
	static long gcd(long a,long b){
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	}



	static long lcm (long a, long b) {
		long g = gcd(a,b);
		return a/g*b;
	}




} Main static final int MOD = 1000000007; MOD 1000000007 static int MAX = 10000000; MAX 10000000 static	ArrayList<TreeNode> tree; tree static HashSet<Integer> set; set static int[] ans; ans static long fac[] = new long[MAX]; fac new long[MAX] MAX static long finv[] = new long[MAX]; finv new long[MAX] MAX static long inv[] = new long[MAX]; inv new long[MAX] MAX public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);			//文字の入力
		int n = sc.nextInt();
		
		HashMap<String,Integer> map = new HashMap<>();
		long ans = 0;

		for(int i = 0;i < n;i++){
			char[] cc = sc.next().toCharArray();
			Arrays.sort(cc);
			String s = new String(cc);
			int num = map.getOrDefault(s, 0);
			map.put(s, num+1);
			if(num >= 1){
				ans += num;
			}
		}
//		COMinit();  					//二項定理デーブル作成
		
//		for(int num:map.values()){
//			ans += COM(num, 2);
//
//		}
		System.out.println(ans);
		
		
		
	} main {
		Scanner sc = new Scanner(System.in);			//文字の入力
		int n = sc.nextInt();
		
		HashMap<String,Integer> map = new HashMap<>();
		long ans = 0;

		for(int i = 0;i < n;i++){
			char[] cc = sc.next().toCharArray();
			Arrays.sort(cc);
			String s = new String(cc);
			int num = map.getOrDefault(s, 0);
			map.put(s, num+1);
			if(num >= 1){
				ans += num;
			}
		}
//		COMinit();  					//二項定理デーブル作成
		
//		for(int num:map.values()){
//			ans += COM(num, 2);
//
//		}
		System.out.println(ans);
		
		
		
	} Scanner sc = new Scanner(System.in); sc new Scanner(System.in) int n = sc.nextInt(); n sc.nextInt() sc.nextInt sc HashMap<String,Integer> map = new HashMap<>(); map new HashMap<>() long ans = 0; ans 0 for(int i = 0;i < n;i++){
			char[] cc = sc.next().toCharArray();
			Arrays.sort(cc);
			String s = new String(cc);
			int num = map.getOrDefault(s, 0);
			map.put(s, num+1);
			if(num >= 1){
				ans += num;
			}
		} int i = 0; int i = 0; i 0 i < n i n i++ i++ i {
			char[] cc = sc.next().toCharArray();
			Arrays.sort(cc);
			String s = new String(cc);
			int num = map.getOrDefault(s, 0);
			map.put(s, num+1);
			if(num >= 1){
				ans += num;
			}
		} {
			char[] cc = sc.next().toCharArray();
			Arrays.sort(cc);
			String s = new String(cc);
			int num = map.getOrDefault(s, 0);
			map.put(s, num+1);
			if(num >= 1){
				ans += num;
			}
		} char[] cc = sc.next().toCharArray(); cc sc.next().toCharArray() sc.next().toCharArray sc.next() sc.next sc Arrays.sort(cc) Arrays.sort Arrays cc String s = new String(cc); s new String(cc) int num = map.getOrDefault(s, 0); num map.getOrDefault(s, 0) map.getOrDefault map s 0 map.put(s, num+1) map.put map s num+1 num 1 if(num >= 1){
				ans += num;
			} num >= 1 num 1 {
				ans += num;
			} ans += num ans num System.out.println(ans) System.out.println System.out System System.out ans String[] args args //テーブルの作成
	static void COMinit() {
		fac[0] = fac[1] = 1;
		finv[0] = finv[1] = 1;
		inv[1] = 1;
		for (int i = 2; i < MAX; i++){
			fac[i] = fac[i - 1] * i % MOD;
			inv[i] = MOD - inv[MOD%i] * (MOD / i) % MOD;
			finv[i] = finv[i - 1] * inv[i] % MOD;
		}
	} COMinit {
		fac[0] = fac[1] = 1;
		finv[0] = finv[1] = 1;
		inv[1] = 1;
		for (int i = 2; i < MAX; i++){
			fac[i] = fac[i - 1] * i % MOD;
			inv[i] = MOD - inv[MOD%i] * (MOD / i) % MOD;
			finv[i] = finv[i - 1] * inv[i] % MOD;
		}
	} fac[0] = fac[1] = 1 fac[0] fac 0 fac[1] = 1 fac[1] fac 1 1 finv[0] = finv[1] = 1 finv[0] finv 0 finv[1] = 1 finv[1] finv 1 1 inv[1] = 1 inv[1] inv 1 1 for (int i = 2; i < MAX; i++){
			fac[i] = fac[i - 1] * i % MOD;
			inv[i] = MOD - inv[MOD%i] * (MOD / i) % MOD;
			finv[i] = finv[i - 1] * inv[i] % MOD;
		} int i = 2; int i = 2; i 2 i < MAX i MAX i++ i++ i {
			fac[i] = fac[i - 1] * i % MOD;
			inv[i] = MOD - inv[MOD%i] * (MOD / i) % MOD;
			finv[i] = finv[i - 1] * inv[i] % MOD;
		} {
			fac[i] = fac[i - 1] * i % MOD;
			inv[i] = MOD - inv[MOD%i] * (MOD / i) % MOD;
			finv[i] = finv[i - 1] * inv[i] % MOD;
		} fac[i] = fac[i - 1] * i % MOD fac[i] fac i fac[i - 1] * i % MOD fac[i - 1] * i fac[i - 1] fac i - 1 i 1 i MOD inv[i] = MOD - inv[MOD%i] * (MOD / i) % MOD inv[i] inv i MOD - inv[MOD%i] * (MOD / i) % MOD MOD inv[MOD%i] * (MOD / i) % MOD inv[MOD%i] * (MOD / i) inv[MOD%i] inv MOD%i MOD i (MOD / i) MOD i MOD finv[i] = finv[i - 1] * inv[i] % MOD finv[i] finv i finv[i - 1] * inv[i] % MOD finv[i - 1] * inv[i] finv[i - 1] finv i - 1 i 1 inv[i] inv i MOD // 二項係数計算
	static	long COM(int n, int k){
		if (n < k) return 0;
		if (n < 0 || k < 0) return 0;
		return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
	} COM {
		if (n < k) return 0;
		if (n < 0 || k < 0) return 0;
		return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
	} if (n < k) return 0; n < k n k return 0; 0 if (n < 0 || k < 0) return 0; n < 0 || k < 0 n < 0 n 0 k < 0 k 0 return 0; 0 return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD; fac[n] * (finv[k] * finv[n - k] % MOD) % MOD fac[n] * (finv[k] * finv[n - k] % MOD) fac[n] fac n (finv[k] * finv[n - k] % MOD) finv[k] * finv[n - k] finv[k] finv k finv[n - k] finv n - k n k MOD MOD int n n int k k static int upperbond(int k,ArrayList<Integer> data){		//k以下で最大の値をdataの中から探し、返す二分探索
		if(data == null){
			return -1;
		}
		int max = data.size();
		int min = -1;
		while(max-min > 1){
			int mid = (max+min)/2;
			if(data.get(mid) <= k){
				min = mid;
			}else{
				max = mid;
			}
		}

		
//		if(min != -1){
//			min = data.get(min);
//		}
		
//		System.out.println(max);
		return min;					//indexを返している
	} upperbond {		//k以下で最大の値をdataの中から探し、返す二分探索
		if(data == null){
			return -1;
		}
		int max = data.size();
		int min = -1;
		while(max-min > 1){
			int mid = (max+min)/2;
			if(data.get(mid) <= k){
				min = mid;
			}else{
				max = mid;
			}
		}

		
//		if(min != -1){
//			min = data.get(min);
//		}
		
//		System.out.println(max);
		return min;					//indexを返している
	} if(data == null){
			return -1;
		} data == null data null {
			return -1;
		} return -1; -1 1 int max = data.size(); max data.size() data.size data int min = -1; min -1 1 while(max-min > 1){
			int mid = (max+min)/2;
			if(data.get(mid) <= k){
				min = mid;
			}else{
				max = mid;
			}
		} max-min > 1 max-min max min 1 {
			int mid = (max+min)/2;
			if(data.get(mid) <= k){
				min = mid;
			}else{
				max = mid;
			}
		} int mid = (max+min)/2; mid (max+min)/2 (max+min) max min 2 if(data.get(mid) <= k){
				min = mid;
			}else{
				max = mid;
			} data.get(mid) <= k data.get(mid) data.get data mid k {
				min = mid;
			} min = mid min mid {
				max = mid;
			} max = mid max mid return min;					//indexを返している min int k k ArrayList<Integer> data data static int lowerbond(int k,ArrayList<Integer> data){		//k以上で最小の値をdataの中から探し、返す二分探索
		if(data == null){
			return -1;
		}
//		System.out.println("lo");
//		System.out.println("lo");
		int max = data.size();
		int min = -1;

		while(max-min > 1){
			int mid = (max+min)/2;
			if(data.get(mid) >= k){
				max = mid;
			}else{
				min = mid;
			}
		}

		return max;			//indexを返している
	} lowerbond {		//k以上で最小の値をdataの中から探し、返す二分探索
		if(data == null){
			return -1;
		}
//		System.out.println("lo");
//		System.out.println("lo");
		int max = data.size();
		int min = -1;

		while(max-min > 1){
			int mid = (max+min)/2;
			if(data.get(mid) >= k){
				max = mid;
			}else{
				min = mid;
			}
		}

		return max;			//indexを返している
	} if(data == null){
			return -1;
		} data == null data null {
			return -1;
		} return -1; -1 1 int max = data.size(); max data.size() data.size data int min = -1; min -1 1 while(max-min > 1){
			int mid = (max+min)/2;
			if(data.get(mid) >= k){
				max = mid;
			}else{
				min = mid;
			}
		} max-min > 1 max-min max min 1 {
			int mid = (max+min)/2;
			if(data.get(mid) >= k){
				max = mid;
			}else{
				min = mid;
			}
		} int mid = (max+min)/2; mid (max+min)/2 (max+min) max min 2 if(data.get(mid) >= k){
				max = mid;
			}else{
				min = mid;
			} data.get(mid) >= k data.get(mid) data.get data mid k {
				max = mid;
			} max = mid max mid {
				min = mid;
			} min = mid min mid return max;			//indexを返している max int k k ArrayList<Integer> data data static int gcd(int a,int b){				//最大公約数を返す
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	} gcd {				//最大公約数を返す
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	} if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		} b == 0 b 0 {
			return a;
		} return a; a {
			return gcd(b, a%b);
		} return gcd(b, a%b); gcd(b, a%b) gcd b a%b a b int a a int b b static long gcd(long a,long b){
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	} gcd {
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	} if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		} b == 0 b 0 {
			return a;
		} return a; a {
			return gcd(b, a%b);
		} return gcd(b, a%b); gcd(b, a%b) gcd b a%b a b long a a long b b static long lcm (long a, long b) {
		long g = gcd(a,b);
		return a/g*b;
	} lcm {
		long g = gcd(a,b);
		return a/g*b;
	} long g = gcd(a,b); g gcd(a,b) gcd a b return a/g*b; a/g*b a/g a g b long a a long b b class Pair implements Comparable{
	int from;
	int end;
	public Pair(int from,int end) {
		this.from = from;
		this.end = end;
		// TODO 自動生成されたコンストラクター・スタブ
	}

	@Override
	public int compareTo(Object other) {
		Pair otherpair = (Pair)other;

		return  from - otherpair.from;
	}








} Pair int from; from int end; end public Pair(int from,int end) {
		this.from = from;
		this.end = end;
		// TODO 自動生成されたコンストラクター・スタブ
	} Pair {
		this.from = from;
		this.end = end;
		// TODO 自動生成されたコンストラクター・スタブ
	} this.from = from this.from this this.from from this.end = end this.end this this.end end int from from int end end @Override
	public int compareTo(Object other) {
		Pair otherpair = (Pair)other;

		return  from - otherpair.from;
	} compareTo {
		Pair otherpair = (Pair)other;

		return  from - otherpair.from;
	} Pair otherpair = (Pair)other; otherpair (Pair)other return  from - otherpair.from; from - otherpair.from from otherpair.from otherpair otherpair.from Object other other Comparable
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Scanner;

import javax.swing.tree.TreeNode;
class Main{


	static final int MOD = 1000000007;

	static int MAX = 10000000;
	static	ArrayList<TreeNode> tree;
	static HashSet<Integer> set;
	static int[] ans;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);			//文字の入力
		int n = sc.nextInt();
		
		HashMap<String,Integer> map = new HashMap<>();
		long ans = 0;

		for(int i = 0;i < n;i++){
			char[] cc = sc.next().toCharArray();
			Arrays.sort(cc);
			String s = new String(cc);
			int num = map.getOrDefault(s, 0);
			map.put(s, num+1);
			if(num >= 1){
				ans += num;
			}
		}
//		COMinit();  					//二項定理デーブル作成
		
//		for(int num:map.values()){
//			ans += COM(num, 2);
//
//		}
		System.out.println(ans);
		
		
		
	}

	static long fac[] = new long[MAX];
	static long finv[] = new long[MAX];
	static long inv[] = new long[MAX];

	

//テーブルの作成
	static void COMinit() {
		fac[0] = fac[1] = 1;
		finv[0] = finv[1] = 1;
		inv[1] = 1;
		for (int i = 2; i < MAX; i++){
			fac[i] = fac[i - 1] * i % MOD;
			inv[i] = MOD - inv[MOD%i] * (MOD / i) % MOD;
			finv[i] = finv[i - 1] * inv[i] % MOD;
		}
	}

	// 二項係数計算
	static	long COM(int n, int k){
		if (n < k) return 0;
		if (n < 0 || k < 0) return 0;
		return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
	}








	static int upperbond(int k,ArrayList<Integer> data){		//k以下で最大の値をdataの中から探し、返す二分探索
		if(data == null){
			return -1;
		}
		int max = data.size();
		int min = -1;
		while(max-min > 1){
			int mid = (max+min)/2;
			if(data.get(mid) <= k){
				min = mid;
			}else{
				max = mid;
			}
		}

		
//		if(min != -1){
//			min = data.get(min);
//		}
		
//		System.out.println(max);
		return min;					//indexを返している
	}

	static int lowerbond(int k,ArrayList<Integer> data){		//k以上で最小の値をdataの中から探し、返す二分探索
		if(data == null){
			return -1;
		}
//		System.out.println("lo");
//		System.out.println("lo");
		int max = data.size();
		int min = -1;

		while(max-min > 1){
			int mid = (max+min)/2;
			if(data.get(mid) >= k){
				max = mid;
			}else{
				min = mid;
			}
		}

		return max;			//indexを返している
	}



	static int gcd(int a,int b){				//最大公約数を返す
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	}
	static long gcd(long a,long b){
		if(b == 0){
			return a;
		}else{
			return gcd(b, a%b);
		}
	}



	static long lcm (long a, long b) {
		long g = gcd(a,b);
		return a/g*b;
	}




}

class Pair implements Comparable{
	int from;
	int end;
	public Pair(int from,int end) {
		this.from = from;
		this.end = end;
		// TODO 自動生成されたコンストラクター・スタブ
	}

	@Override
	public int compareTo(Object other) {
		Pair otherpair = (Pair)other;

		return  from - otherpair.from;
	}








}




