Buggy python submission (verdict: Time Limit Exceeded):
# -*- coding:utf-8 -*-

def solve():
    N = int(input())
    dicts = []
    for i in range(N):
        s = input()
        d = {}
        for moji in s:
            if not moji in d:
                d[moji] = 0
            d[moji] += 1
        dicts.append(d)

    ans = 0    
    done = set()
    for i in range(N):
        if i in done: continue
        d1 = dicts[i]
        ret = 0
        for j in range(i+1, N):
            d2 = dicts[j]
            if d1 == d2:
                done.add(j)
                ret += 1
        # ret + (ret-1) + ... + 1 を計算する
        ans += (ret+1)*ret/2 # 和の公式

    print(int(ans))



if __name__ == "__main__":
    solve()


Fixed submission:
# -*- coding:utf-8 -*-
"""解説PDF
s1 = "abaaa" をソートして "aaaab" を得る。
s2 = "dddcc" をソートして "ccddd" を得る。
s3 = "baaaa" をソートして "aaaab" を得る。これはすでに一回現れているので答えに1を足す。
s4 = "cdddc" をソートして "ccddd" を得る。これはすでに一回現れているので答えに1を足す。
s5 = "aaaab" をソートして "aaaab" を得る。これはすでに二回現れているので答えに2を足す。

というふうにやる。

「これはすでにK回現れているので」は、ハッシュテーブルでやればよい

"""
def solve():
    N = int(input())
    d = {}
    for i in range(N):
        s = "".join(sorted(input()))
        if not s in d:
            d[s] = 0
        d[s] += 1

    ans = 0
    for s, value in d.items():
        if value >= 2:
            # 和の公式で答えにタス
            ans += (value-1+1)*(value-1)/2
    print(int(ans))


if __name__ == "__main__":
    solve()

Buggy python submission (verdict: Time Limit Exceeded):
# -*- coding:utf-8 -*-

def solve():
    N = int(input())
    dicts = []
    for i in range(N):
        s = input()
        d = {}
        for moji in s:
            if not moji in d:
                d[moji] = 0
            d[moji] += 1
        dicts.append(d)

    ans = 0    
    done = set()
    for i in range(N):
        if i in done: continue
        d1 = dicts[i]
        ret = 0
        for j in range(i+1, N):
            d2 = dicts[j]
            if d1 == d2:
                done.add(j)
                ret += 1
        # ret + (ret-1) + ... + 1 を計算する
        ans += (ret+1)*ret/2 # 和の公式

    print(int(ans))



if __name__ == "__main__":
    solve()


Fixed submission:
# -*- coding:utf-8 -*-
"""解説PDF
s1 = "abaaa" をソートして "aaaab" を得る。
s2 = "dddcc" をソートして "ccddd" を得る。
s3 = "baaaa" をソートして "aaaab" を得る。これはすでに一回現れているので答えに1を足す。
s4 = "cdddc" をソートして "ccddd" を得る。これはすでに一回現れているので答えに1を足す。
s5 = "aaaab" をソートして "aaaab" を得る。これはすでに二回現れているので答えに2を足す。

というふうにやる。

「これはすでにK回現れているので」は、ハッシュテーブルでやればよい

"""
def solve():
    N = int(input())
    d = {}
    for i in range(N):
        s = "".join(sorted(input()))
        if not s in d:
            d[s] = 0
        d[s] += 1

    ans = 0
    for s, value in d.items():
        if value >= 2:
            # 和の公式で答えにタス
            ans += (value-1+1)*(value-1)/2
    print(int(ans))


if __name__ == "__main__":
    solve()

Buggy python submission (verdict: Time Limit Exceeded):
# -*- coding:utf-8 -*-

def solve():
    N = int(input())
    dicts = []
    for i in range(N):
        s = input()
        d = {}
        for moji in s:
            if not moji in d:
                d[moji] = 0
            d[moji] += 1
        dicts.append(d)

    ans = 0    
    for i in range(N):
        d1 = dicts[i]
        for j in range(i+1, N):
            d2 = dicts[j]
            ans += 1 if d1 == d2 else 0

    print(ans)



if __name__ == "__main__":
    solve()


Fixed submission:
# -*- coding:utf-8 -*-
"""解説PDF
s1 = "abaaa" をソートして "aaaab" を得る。
s2 = "dddcc" をソートして "ccddd" を得る。
s3 = "baaaa" をソートして "aaaab" を得る。これはすでに一回現れているので答えに1を足す。
s4 = "cdddc" をソートして "ccddd" を得る。これはすでに一回現れているので答えに1を足す。
s5 = "aaaab" をソートして "aaaab" を得る。これはすでに二回現れているので答えに2を足す。

というふうにやる。

「これはすでにK回現れているので」は、ハッシュテーブルでやればよい

"""
def solve():
    N = int(input())
    d = {}
    for i in range(N):
        s = "".join(sorted(input()))
        if not s in d:
            d[s] = 0
        d[s] += 1

    ans = 0
    for s, value in d.items():
        if value >= 2:
            # 和の公式で答えにタス
            ans += (value-1+1)*(value-1)/2
    print(int(ans))


if __name__ == "__main__":
    solve()