Problem:


Score : 700 points

Problem Statement

Limak can repeatedly remove one of the first two characters of a string,
    for example abcxyx \rightarrow acxyx \rightarrow cxyx \rightarrow cyx.

You are given N different strings S_1, S_2, \ldots, S_N.
Among N \cdot (N-1) / 2 pairs (S_i, S_j),
    in how many pairs could Limak obtain one string from the other?

Constraints

2 \leq N \leq 200\,000

S_i consists of lowercase English letters a-z.

S_i \neq S_j

1 \leq |S_i|

|S_1| + |S_2| + \ldots + |S_N| \leq 10^6

Input

Input is given from Standard Input in the following format.

N
S_1
S_2
\vdots
S_N

Output

Print the number of unordered pairs (S_i, S_j)
    where i \neq j and Limak can obtain one string from the other.

Sample Input 1

3
abcxyx
cyx
abc

Sample Output 1

1

The only good pair is (abcxyx, cyx).

Sample Input 2

6
b
a
abc
c
d
ab

Sample Output 2

5

There are five good pairs: (b, abc), (a, abc), (abc, c), (b, ab), (a, ab).



Sample input:
3
abcxyx
cyx
abc


Sample output:
1

Submission status: Accepted

Solution code:
import sys
input = sys.stdin.readline

base = 1000
mod = 10**23 + 117

N = int(input())
S = [input().rstrip()[::-1] for _ in range(N)]
S.sort(key=lambda s: -len(s))
cnt = {}
ans = 0
one = [0] * 26
for s in S:
    n = len(s)
    if n == 1:
        ans += one[ord(s[0]) - ord('a')]
        continue
    hashes = [0] * (n - 1)
    hashes[0] = ord(s[0])
    for i in range(1, n - 1):
        hashes[i] = (hashes[i-1] * base + ord(s[i])) % mod
    if hashes[-1] in cnt:
        ans += cnt[hashes[-1]][ord(s[-1]) - ord('a')]
    found = [0] * 26
    found[ord(s[-1]) - ord('a')] = 1
    for i in range(n - 2, 0, -1):
        found[ord(s[i]) - ord('a')] = 1
        if hashes[i-1] not in cnt:
            cnt[hashes[i-1]] = [0] * 26
        for c in range(26):
            cnt[hashes[i-1]][c] += found[c]
    found[ord(s[0]) - ord('a')] = 1
    for c in range(26):
        one[c] += found[c]
print(ans)

Submission status: Accepted

Solution code:
import sys
input = sys.stdin.readline

base = 27
mod = (1 << 61) - 1

N = int(input())
S = [input().rstrip()[::-1] for _ in range(N)]
S.sort(key=lambda s: -len(s))
cnt = {}
ans = 0
one = [0] * 26
for s in S:
    n = len(s)
    if n == 1:
        ans += one[ord(s[0]) - ord('a')]
        continue
    hashes = [0] * (n - 1)
    hashes[0] = ord(s[0]) - ord('a') + 1
    for i in range(1, n - 1):
        hashes[i] = (hashes[i-1] * base + ord(s[i]) - ord('a') + 1) % mod
    if hashes[-1] in cnt:
        ans += cnt[hashes[-1]][ord(s[-1]) - ord('a')]
    found = [0] * 26
    found[ord(s[-1]) - ord('a')] = 1
    for i in range(n - 2, 0, -1):
        found[ord(s[i]) - ord('a')] = 1
        if hashes[i-1] not in cnt:
            cnt[hashes[i-1]] = [0] * 26
        for c in range(26):
            cnt[hashes[i-1]][c] += found[c]
    found[ord(s[0]) - ord('a')] = 1
    for c in range(26):
        one[c] += found[c]
print(ans)

Submission status: Accepted

Solution code:
import sys
input = sys.stdin.readline

base = 1999849216943526259
mod = (1 << 61) - 1

N = int(input())
S = [input().rstrip()[::-1] for _ in range(N)]
S.sort(key=lambda s: -len(s))
cnt = {}
ans = 0
one = [0] * 26
for s in S:
    n = len(s)
    if n == 1:
        ans += one[ord(s[0]) - ord('a')]
        continue
    hashes = [0] * (n - 1)
    hashes[0] = ord(s[0])
    for i in range(1, n - 1):
        hashes[i] = (hashes[i-1] * base + ord(s[i])) % mod
    if hashes[-1] in cnt:
        ans += cnt[hashes[-1]][ord(s[-1]) - ord('a')]
    found = [0] * 26
    found[ord(s[-1]) - ord('a')] = 1
    for i in range(n - 2, 0, -1):
        found[ord(s[i]) - ord('a')] = 1
        if hashes[i-1] not in cnt:
            cnt[hashes[i-1]] = [0] * 26
        for c in range(26):
            cnt[hashes[i-1]][c] += found[c]
    found[ord(s[0]) - ord('a')] = 1
    for c in range(26):
        one[c] += found[c]
print(ans)

Submission status: Accepted

Solution code:
class SparseTable():
    def __init__(self,A):
        N=len(A)
        n=N.bit_length()
        self.table=[[-1 for i in range(n)] for i in range(N)]

        for i in range(N):
            self.table[i][0]=A[i]

        for j in range(1,n):
            for i in range(0,N-2**j+1):
                f=self.table[i][j-1]
                s=self.table[i+2**(j-1)][j-1]
                self.table[i][j]=min(f,s)

    def query(self,s,t):
        b=t-s+1
        m=b.bit_length()-1
        return min(self.table[s][m],self.table[t-2**m+1][m])

class BIT():
    def __init__(self,n):
        self.BIT=[0]*(n+1)
        self.num=n

    def query(self,idx):
        res_sum = 0
        while idx > 0:
            res_sum += self.BIT[idx]
            idx -= idx&(-idx)
        return res_sum

    #Ai += x O(logN)
    def update(self,idx,x):
        while idx <= self.num:
            self.BIT[idx] += x
            idx += idx&(-idx)
        return

alphabetlist=['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
dic={i:e for e,i in enumerate(alphabetlist)}


import sys

input=sys.stdin.readline

N=int(input())
S=[input().rstrip() for i in range(N)]
for i in range(N):
    temp=[S[i][-j-1] for j in range(len(S[i]))]
    S[i]="".join(temp)
S.sort()

def Solve(S):
    exact=[0 for i in range(N)]
    for i in range(1,N):
        id=0
        limit=min(len(S[i]),len(S[i-1]))
        while limit>id and S[i][id]==S[i-1][id]:
            id+=1
        exact[i]=id

    lastappear=[[-1 for i in range(26)] for j in range(N)]
    for i in range(N):
        for j in range(len(S[i])):
            id=dic[S[i][j]]
            lastappear[i][id]=j

    Sparse=SparseTable(exact)

    def cond(s,n,val):
        if n==N or s==-1:
            return False
        check=Sparse.query(s,n)
        return check>=val

    query=[]
    bit=[BIT(N) for i in range(26)]
    res=-N
    for i in range(N):
        L,R=i+1,i+1
        if i!=N-1 and exact[i+1]>=len(S[i])-1:
            start=i+1
            end=N
            while end-start>1:
                test=(end+start)//2
                if cond(i+1,test,len(S[i])-1):
                    start=test
                else:
                    end=test
            R=start+1
        if i!=0 and exact[i]>=len(S[i])-1:
            start=-1
            end=i
            while end-start>1:
                test=(end+start)//2
                if cond(test,i,len(S[i])-1):
                    end=test
                else:
                    start=test
            L=end
        query.append((len(S[i])-1,L,R,dic[S[i][-1]]))
        for j in range(26):
            if lastappear[i][j]!=-1:
                query.append((lastappear[i][j],N+1,i+1,j))

    query.sort(reverse=True)

    for val,l,r,id in query:
        if l==N+1:
            bit[id].update(r,1)
        else:
            res+=bit[id].query(r)-bit[id].query(l-1)
    return res

ans=0
ans+=Solve(S)
print(ans)

Submission status: Accepted

Solution code:
from collections import Counter
from string import ascii_lowercase

n = int(input())
sss = [input() for _ in range(n)]
flags = {c: 1 << (ord(c) - 97) for c in ascii_lowercase}

trie_chr = [-1]
trie_children = [{}]
trie_fin = [0]
l = 1

for s in sss:
    node = 0
    for i in range(len(s) - 1, 0, -1):
        c = ord(s[i]) - 97
        if c in trie_children[node]:
            node = trie_children[node][c]
        else:
            trie_chr.append(c)
            trie_children.append({})
            trie_fin.append(0)
            trie_children[node][c] = l
            node = l
            l += 1
    trie_fin[node] |= flags[s[0]]

ans = 0

for s in sss:
    cnt = Counter(s)
    flag = 0
    for c in cnt:
        flag |= flags[c]
    node = 0
    if len(s) > 1 and trie_fin[node] > 0:
        ans += bin(trie_fin[node] & flag).count('1')

    for i in range(len(s) - 1, 1, -1):
        c = s[i]
        cnt[c] -= 1
        if cnt[c] == 0:
            flag ^= flags[c]
        k = ord(c) - 97
        node = trie_children[node][k]
        if trie_fin[node] > 0:
            ans += bin(trie_fin[node] & flag).count('1')

print(ans)

Submission status: Accepted

Solution code:
from collections import Counter
from string import ascii_lowercase

n = int(input())
sss = [input() for _ in range(n)]
flags = {c: 1 << (ord(c) - 97) for c in ascii_lowercase}

trie_chr = [-1]
trie_children = [{}]
trie_counter = [0]
trie_fin = [0]
l = 1

for s in sss:
    node = 0
    trie_counter[node] += 1
    for i in range(len(s) - 1, 0, -1):
        c = ord(s[i]) - 97
        if c in trie_children[node]:
            node = trie_children[node][c]
            trie_counter[node] += 1
        else:
            trie_chr.append(c)
            trie_children.append({})
            trie_fin.append(0)
            trie_children[node][c] = l
            trie_counter.append(1)
            node = l
            l += 1
    trie_fin[node] |= flags[s[0]]

ans = 0

for s in sss:
    cnt = Counter(s)
    flag = 0
    for c in cnt:
        flag |= flags[c]
    node = 0
    if len(s) > 1 and trie_fin[node] > 0:
        ans += bin(trie_fin[node] & flag).count('1')

    for i in range(len(s) - 1, 1, -1):
        c = s[i]
        cnt[c] -= 1
        if cnt[c] == 0:
            flag ^= flags[c]
        k = ord(c) - 97
        node = trie_children[node][k]
        if trie_counter[node] == 1:
            break
        if trie_fin[node] > 0:
            ans += bin(trie_fin[node] & flag).count('1')

print(ans)

Submission status: Accepted

Solution code:
import sys
sys.setrecursionlimit(10**7) #再帰関数の上限,10**5以上の場合python
import math
from copy import copy, deepcopy
from copy import deepcopy as dcp
from operator import itemgetter
from bisect import bisect_left, bisect, bisect_right#2分探索
#bisect_left(l,x), bisect(l,x)#aはソート済みである必要あり。aの中からx未満の要素数を返す。rightだと以下
from collections import deque, defaultdict
#deque(l), pop(), append(x), popleft(), appendleft(x)
#q.rotate(n)で → にn回ローテート
from collections import Counter#文字列を個数カウント辞書に、
#S=Counter(l),S.most_common(x),S.keys(),S.values(),S.items()
from itertools import accumulate,combinations,permutations,product#累積和
#list(accumulate(l))
from heapq import heapify,heappop,heappush
#heapify(q),heappush(q,a),heappop(q) #q=heapify(q)としないこと、返り値はNone
from functools import reduce,lru_cache#pypyでもうごく
#@lru_cache(maxsize = None)#maxsizeは保存するデータ数の最大値、2**nが最も高効率
from decimal import Decimal

def input(): 
    x=sys.stdin.readline()
    return x[:-1] if x[-1]=="\n" else x
def printe(*x):print("## ",*x,file=sys.stderr)
def printl(li): _=print(*li, sep="\n") if li else None
def argsort(s, return_sorted=False): 
    inds=sorted(range(len(s)), key=lambda k: s[k])
    if return_sorted: return inds, [s[i] for i in inds]
    return inds
def alp2num(c,cap=False): return ord(c)-97 if not cap else ord(c)-65
def num2alp(i,cap=False): return chr(i+97) if not cap else chr(i+65)
def matmat(A,B):
    K,N,M=len(B),len(A),len(B[0])
    return [[sum([(A[i][k]*B[k][j]) for k in range(K)]) for j in range(M)] for i in range(N)]
def matvec(M,v):
    N,size=len(v),len(M)
    return [sum([M[i][j]*v[j] for j in range(N)]) for i in range(size)]
def T(M):
    n,m=len(M),len(M[0])
    return [[M[j][i] for j in range(n)] for i in range(m)]
def binr(x): return bin(x)[2:]
def bitcount(x): #xは64bit整数
    x= x - ((x >> 1) & 0x5555555555555555)
    x= (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333)
    x= (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f 
    x+= (x >> 8); x+= (x >> 16); x+= (x >> 32) 
    return x & 0x7f
import random
class rh:#base,max_n=ありうる文字の最大長,convertを指定すること
    def __init__(self,base,max_n):#baseとmaxnを指定すること。baseは偶数(modが奇数)
        self.mod=random.randrange(1<<54-1,1<<55-1,2)#奇数、衝突させられないよう乱数で生成
        self.base=int(base*0.5+0.5)*2#偶数,英小文字なら26とか
        self.max_n=max_n
        self.pows1=[1]*(max_n+1)
        cur1=1
        for i in range(1,max_n+1):
            cur1=cur1*base%self.mod
            self.pows1[i]=cur1

    def convert(self,c): return alp2num(c,False)#大文字の場合Trueにする
    
    def get(self, s):#特定の文字のhash. O(|s|)
        n=len(s)
        mod=self.mod
        si=[self.convert(ss) for ss in s]
        h1=0
        for i in range(n):h1=(h1+si[i]*self.pows1[n-1-i])%mod
        return h1
    
    def get_roll(self, s, k, uroboros=False):#ローリングハッシュ,sの各文字を始点とした長さkの部分文字のhash値をすべて得る,O(|s|)
        #uroboros: trueの場合文字sを循環させ、n個のハッシュ値を得る。 falseの場合n-k+1個
        n=len(s)
        maxitr=n-k+1
        if uroboros: maxitr=n
    
        si=[self.convert(ss) for ss in s]
        mod=self.mod
        h1=0
        for i in range(k):h1=(h1+si[i%n]*self.pows1[k-1-i])%mod
        hs=[0]*maxitr
        hs[0]=h1
        mbase1=self.pows1[k]
        base=self.base
        
        for i in range(1,maxitr): 
            front=si[i-1];back=si[(i+k-1)%n]
            h1=(h1*base-front*mbase1+back)%mod
            hs[i]=h1
        return hs

def main():
    mod = random.randrange(1<<54-1,1<<55-1,2)
    #w.sort(key=itemgetter(1),reverse=True)  #二個目の要素で降順並び替え

    N = int(input())
    #mod=1000000007
    mod2=999999937

    #N, K = map(int, input().split())
    #A = tuple(map(int, input().split())) #1行ベクトル
    L=["" for _ in range(N)]
    ll=[0]*N
    for i in range(N):
        s=input()
        ls=len(s)
        ll[i]=ls
        L[i]=s

    #S = tuple(tuple(map(int, input().split())) for i in range(N)) #改行行列

    inds=argsort(ll)
    d=Counter()
    ans=0
    base=26

    for im in inds:
        
        s=L[im]

        ls=len(s)
        cur=0
        cur2=0
        se=Counter(s)
        #printe(se)
        for i in range(ls):
            for a,val in se.items():
                if val:
                    ai=alp2num(a)
                    ans+=d[(i+1,(cur*base+ai)%mod)]
                    
            si=s[-1-i]
            sin=alp2num(si)
            cur=(cur*base+sin)%mod
            #cur2=(cur2*base+sin)%mod2

            se[si]-=1

        d[(ls,cur)]+=1

    print(ans)
            





if __name__ == "__main__":
    main()

Submission status: Accepted

Solution code:
import sys
def input():
	return sys.stdin.readline()[:-1]

BASE, MOD = 1999849216943526259, (1<<61)-1

d = dict()
ans = 0
ss = [str(input())[::-1] for _ in range(int(input()))]
zero = [0 for _ in range(26)]
ss.sort(key=lambda x: -len(x))
for s in ss:
	n = len(s)
	if n == 1:
		ans += zero[ord(s[n-1])-97]
	else:
		hashes = [0 for _ in range(n-1)]
		hashes[0] = ord(s[0])
		for i in range(1, n-1):
			hashes[i] = (hashes[i-1] * BASE + ord(s[i])) % MOD
		if hashes[n-2] in d:
			ans += d[hashes[n-2]][ord(s[n-1])-97]
		alph = [0 for _ in range(26)]
		alph[ord(s[n-1])-97] = 1
		for i in range(n-2, 0, -1):
			alph[ord(s[i])-97] = 1
			if hashes[i-1] not in d:
				d[hashes[i-1]] = [0 for _ in range(26)]
			for j, a in enumerate(alph):
				d[hashes[i-1]][j] += a
		alph[ord(s[0])-97] = 1
		for j, a in enumerate(alph):
			zero[j] += a
print(ans)

Submission status: Accepted

Solution code:
inn = lambda : int(input())
ins = lambda : input().strip()
DBG = True # and False

def ddprint(x):
  if DBG:
    print(x)

import sys,resource
def setrlim():
  sys.setrecursionlimit(250000)
  soft,hard = resource.getrlimit(resource.RLIMIT_STACK)
  # setrlimit works on ubuntu (and atcoder), but not on WSL
  resource.setrlimit(resource.RLIMIT_STACK, (128*1024*1024,hard))

def dfs(l,k):
    global ans
    #ddprint(f"dfs {k=} {l=} - - - -")
    ll = [[] for i in range(26)]
    x = [0]*26
    for z in l:
        #ddprint(f"lsz {ls[z]} {z=} {k=}")
        c = ord(ls[z][-k-1])-orda
        if len(ls[z])==k+1:
            x[c] += 1
        else:
            ll[c].append(z)
    #ddprint(f"{x=} {ll=}")
    for c in range(26):
        for z in l:
            #if len(ls)==2:
            #    ddprint(f" z1 {z[1]} {k=} {c=} fst {first[z[1]][c]}")
            if first[z][c]>=k and len(ls[z])>k+1:
                ans += x[c]
                #if x[c]>0:
                #    ddprint(f"ans += {x[c]}")
    for c in range(26):
        if len(ll[c])>1:
            dfs(ll[c],k+1)

setrlim()
n = inn()
ls = []
first = [[-1]*26 for i in range(n)]
orda = ord('a')
for i in range(n):
    s = ins()
    ls.append(s)
    for c in range(26):
        p = s.find(chr(orda+c))
        first[i][c] = (len(s)-1-p) if p>=0 else -1
#ddprint(f"{ls=}")
#ddprint(f"{first=}")
ans = 0
dfs(list(range(n)),0)
print(ans)

Submission status: Accepted

Solution code:
import sys
def input():
	return sys.stdin.buffer.readline()[:-1]

BASE, MOD = 1999849216943526259, (1<<61)-1

d = dict()
ans = 0
ss = [str(input())[2:-1][::-1] for _ in range(int(input()))]
zero = [0 for _ in range(26)]
ss.sort(key=lambda x: -len(x))
for s in ss:
	n = len(s)
	if n == 1:
		ans += zero[ord(s[n-1])-97]
	else:
		hashes = [0 for _ in range(n-1)]
		hashes[0] = ord(s[0])
		for i in range(1, n-1):
			hashes[i] = (hashes[i-1] * BASE + ord(s[i])) % MOD
		if hashes[n-2] in d:
			ans += d[hashes[n-2]][ord(s[n-1])-97]
		alph = [0 for _ in range(26)]
		alph[ord(s[n-1])-97] = 1
		for i in range(n-2, 0, -1):
			alph[ord(s[i])-97] = 1
			if hashes[i-1] not in d:
				d[hashes[i-1]] = [0 for _ in range(26)]
			for j, a in enumerate(alph):
				d[hashes[i-1]][j] += a
		alph[ord(s[0])-97] = 1
		for j, a in enumerate(alph):
			zero[j] += a
print(ans)

Submission status: Accepted

Solution code:
import sys

sys.setrecursionlimit(10**7)

N = int(input())
S = []
a = ord('a')
for _ in range(N):
  S.append([ord(c) - a for c in input()][::-1])

_end = -1  #'_'
_count = -2 #'#'
def get_count(root):
  to_visit = [root]
  while to_visit:
    current = to_visit[-1]
    if _count in current:
      to_visit.pop()
      continue
    else:
      done = True
      c = [0] * 26 + [1 if _end in current else 0]
      for k, n in current.items():
        if k in (_end, _count):
          continue
        if _count not in n:
          done = False
          break
        if k not in (_end, _count):
          cc = n[_count]
          #print(k, cc)
          for i, v in enumerate(cc):
            if i == k:
              c[k] += cc[-1]
            else:
              c[i] += v
      if done:
        current[_count] = c
        to_visit.pop()
      else:
        for k, v in current.items():
          if k not in (_end, _count):
            to_visit.append(v)
  return current[_count]
        
  
  
  if _count in root:
    return root[_count]
  else:
    c = [0] * 26 + [1 if _end in root else 0]
    for k, n in root.items():
      if k not in (_end, _count):
        cc = get_count(n)
        #print(k, cc)
        for i, v in enumerate(cc):
          if i == k:
            c[k] += cc[-1]
          else:
            c[i] += v
    root[_count] = c
    return c
    
def make_trie(words):
  root = dict()
  for word in words:
    current_dict = root
    for letter in word:
      #letter = ord(letter)
      current_dict = current_dict.setdefault(letter, {})
    current_dict[_end] = _end
 
  return root

def get_subtree(trie, word):
  current_dict = trie
  for letter in word:
    #letter = ord(letter)
    if letter not in current_dict:
      return {}
    current_dict = current_dict[letter]
  return current_dict
  
def in_trie(trie, word):
  return _end in get_subtree(trie, word)

trie = make_trie(S)
#print(trie)
#print(get_subtree(trie, 'cy'))
#print(in_trie(trie, 'cy'))
#print(in_trie(trie, 'cyx'))

ans = 0
for s in S:
  count = get_count(get_subtree(trie, s[:-1]))
  #print(s, '#', count[s[-1]], count)
  ans += count[s[-1]]

print((ans - N))

Submission status: Accepted

Solution code:
import sys;input=sys.stdin.readline
N, = map(int, input().split())
MOD=67280421310721
S = []
for _ in range(N):
    s = input().strip()
    S.append(s)
S.sort(key=lambda x:len(x))
D = dict()
dd = set()
R = 0
for s in S:
    l = len(s)
    d = [0]*26
    for c in dd:
        d[c] += 1
    tmp=0
    for i in range(l-1, -1, -1):
        ee = ord(s[i]) - 97
        tmp = 100*tmp+(ee+1)
        tmp %= MOD
        R += d[ee]
        d[ee] = 0
        if tmp in D:
            for c in D[tmp]:
                d[c] += 1
        if i == 1:
            nn = tmp
    if l != 1:
        if nn not in D:
            D[nn] = set()
        D[nn].add(ee)
    else:
        dd.add(ee)
print(R)

Submission status: Accepted

Solution code:
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**9)

def solve():
    ordA = ord('a')

    N = int(input())
    Ass = []
    for _ in range(N):
        Ss = input().rstrip()
        As = [ord(S)-ordA for S in Ss[::-1]]
        Ass.append(As)

    Ass.sort(key=lambda x: len(x))

    fsss = []
    for As in Ass:
        fss = []
        fs = [0] * 26
        for i in reversed(range(len(As))):
            fs[As[i]] = 1
            fss.append(fs[:])
        fsss.append(fss[::-1])

    ans = 0
    nodes = []
    nodes.append([-1]*26)
    nums = []
    nums.append([0]*26)
    numNode = 1
    for As, fss in zip(Ass, fsss):
        lenA = len(As)
        iNode = 0
        for j in range(lenA):
            A = As[j]
            fs = fss[j]
            for c in range(26):
                if fs[c]:
                    ans += nums[iNode][c]

            if nodes[iNode][A] == -1:
                nodes.append([-1]*26)
                nums.append([0]*26)
                nodes[iNode][A] = numNode
                numNode += 1
            else:
                pass

            if j == lenA-1:
                nums[iNode][As[-1]] += 1

            iNode = nodes[iNode][A]

    print(ans)


solve()

Submission status: Accepted

Solution code:
import sys


input = sys.stdin.readline
N = int(input())
S = [input().replace('\n', '')[::-1] for _ in range(N)]
S1 = []
Slong = []
for s in S:
    if len(s) == 1:
        S1.append(s)
    else:
        Slong.append(s)

ans = 0
# 2文字以上同士のついを数える
Slong = sorted(Slong, key=lambda x: x[:-1])
for i in range(len(Slong)):
    s = Slong[i]
    j = i + 1
    n = len(s)-1
    while j<len(Slong) and Slong[j][:n] == s[:n]:
        ans += Slong[j][n:].find(s[-1]) != -1
        j += 1

# 1文字同士
S1 = sorted(S1)
for i in range(len(S1)):
    s = S1[i]
    j = i + 1
    while j<len(S1) and S1[j] == s:
        ans += 1
        j += 1


# 1->2以上
a2z = [chr(i) for i in range(97, 97+26)]
wcnt = {i: 0for i in a2z}
for s in Slong:
    for c in set(s):
        wcnt[c] += 1
for s in S1:
    ans += wcnt[s]
print(ans)

Submission status: Accepted

Solution code:
import sys
import math
import copy
import heapq
from functools import cmp_to_key
from bisect import bisect_left, bisect_right
from collections import defaultdict, deque, Counter
sys.setrecursionlimit(1000000)

# input aliases
input = sys.stdin.readline
getS = lambda: input().strip()
getN = lambda: int(input())
getList = lambda: list(map(int, input().split()))
getZList = lambda: [int(x) - 1 for x in input().split()]

INF = float("inf")
MOD = 10**9 + 7
divide = lambda x: pow(x, MOD-2, MOD)

def nck(n, k, kaijyo):
    return (npk(n, k, kaijyo) * divide(kaijyo[k])) % MOD

def npk(n, k, kaijyo):
    if k == 0 or k == n:
        return n % MOD
    return (kaijyo[n] * divide(kaijyo[n-k])) % MOD

def fact_and_inv(SIZE):
    inv = [0] * SIZE  # inv[j] = j^{-1} mod MOD
    fac = [0] * SIZE  # fac[j] = j! mod MOD
    finv = [0] * SIZE  # finv[j] = (j!)^{-1} mod MOD
    inv[1] = 1
    fac[0] = fac[1] = 1
    finv[0] = finv[1] = 1
    for i in range(2, SIZE):
        inv[i] = MOD - (MOD // i) * inv[MOD % i] % MOD
        fac[i] = fac[i - 1] * i % MOD
        finv[i] = finv[i - 1] * inv[i] % MOD

    return fac, finv

def renritsu(A, Y):
    # example 2x + y = 3, x + 3y = 4
    # A = [[2,1], [1,3]])
    # Y = [[3],[4]] または [3,4]
    A = np.matrix(A)
    Y = np.matrix(Y)
    Y = np.reshape(Y, (-1, 1))
    X = np.linalg.solve(A, Y)

    # [1.0, 1.0]
    return X.flatten().tolist()[0]

class TwoDimGrid:
    # 2次元座標 -> 1次元
    def __init__(self, h, w, wall="#"):
        self.h = h
        self.w = w
        self.size = (h+2) * (w+2)
        self.wall = wall
        self.get_grid()
        # self.init_cost()

    def get_grid(self):
        grid = [self.wall * (self.w + 2)]
        for i in range(self.h):
            grid.append(self.wall + getS() + self.wall)

        grid.append(self.wall * (self.w + 2))
        self.grid = grid
    def init_cost(self):
        self.cost = [INF] * self.size

    def pos(self, x, y):
        # 壁も含めて0-indexed 元々の座標だけ考えると1-indexed
        return y * (self.w + 2) + x
    def getgrid(self, x, y):
        return self.grid[y][x]
    def get(self, x, y):
        return self.cost[self.pos(x, y)]
    def set(self, x, y, v):
        self.cost[self.pos(x, y)] = v
        return
    def show(self):
        for i in range(self.h+2):
            print(self.cost[(self.w + 2) * i:(self.w + 2) * (i+1)])
    def showsome(self, tgt):
        for t in tgt:
            print(t)
        return
    def showsomejoin(self, tgt):
        for t in tgt:
            print("".join(t))
        return

    def search(self):
        grid = self.grid
        move = [(0, 1), (0, -1), (1, 0), (-1, 0)]
        move_eight = [(0, 1), (0, -1), (1, 0), (-1, 0), (1, 1), (1, -1), (-1, 1), (-1, -1)]
        # for i in range(1, self.h+1):
        #     for j in range(1, self.w+1):
        #         cx, cy = j, i
        #         for dx, dy in move_eight:
        #             nx, ny = dx + cx, dy + cy
def getc():
    a = ord("a")
    ret = dict()
    for i in range(1, 27):
        ret[chr(a - 1 + i)] = i
    # print(ret)
    return ret

def solve():
    MOD = 67280421310721
    # a = ["a", "z", "za", "aza"]
    # a.sort()
    # pritn(a)
    n = getN()
    lis = []
    for i in range(n):
        S = list(getS())
        S.reverse()
        lis.append(S)


    lis.sort(key=lambda x: len(x))
    # lis.sort()
    # print(lis)
    ans = 0
    single = dict()
    hash = dict()
    cd = getc()
    for s in lis:
        if len(s) == 1:
            single[s[0]] = 1
            continue
        base = 27
        tmp = 0
        hakken = defaultdict(int)
        singlec = copy.deepcopy(single)
        for c in s[:-1]:
            if c in hakken:
                ans += hakken[c]
                del hakken[c]
            if c in singlec:
                ans += singlec[c]
                del singlec[c]

            tmp = tmp + (base * cd[c]) % MOD
            # tmp %= MOD
            base = (base * 27) % MOD
            # base %= MOD
            if tmp in hash:
                for tgt in hash[tmp]:
                    hakken[tgt] += 1


        if s[-1] in hakken:
            ans += hakken[s[-1]]
        if s[-1] in singlec:
            ans +=singlec[s[-1]]

        if tmp in hash:
            hash[tmp].append(s[-1])
        else:
            hash[tmp] = [s[-1]]
        # print(ans, s, single)

    print(ans)







def main():
    n = getN()
    for _ in range(n):
        solve()

    return
if __name__ == "__main__":
    # main()
    solve()

Submission status: Accepted

Solution code:
import sys
sys.setrecursionlimit(10**7) #再帰関数の上限,10**5以上の場合python
import math
from copy import copy, deepcopy
from copy import deepcopy as dcp
from operator import itemgetter
from bisect import bisect_left, bisect, bisect_right#2分探索
#bisect_left(l,x), bisect(l,x)#aはソート済みである必要あり。aの中からx未満の要素数を返す。rightだと以下
from collections import deque, defaultdict
#deque(l), pop(), append(x), popleft(), appendleft(x)
#q.rotate(n)で → にn回ローテート
from collections import Counter#文字列を個数カウント辞書に、
#S=Counter(l),S.most_common(x),S.keys(),S.values(),S.items()
from itertools import accumulate,combinations,permutations,product#累積和
#list(accumulate(l))
from heapq import heapify,heappop,heappush
#heapify(q),heappush(q,a),heappop(q) #q=heapify(q)としないこと、返り値はNone
from functools import reduce,lru_cache#pypyでもうごく
#@lru_cache(maxsize = None)#maxsizeは保存するデータ数の最大値、2**nが最も高効率
from decimal import Decimal

def input(): 
    x=sys.stdin.readline()
    return x[:-1] if x[-1]=="\n" else x
def printe(*x):print("## ",*x,file=sys.stderr)
def printl(li): _=print(*li, sep="\n") if li else None
def argsort(s, return_sorted=False): 
    inds=sorted(range(len(s)), key=lambda k: s[k])
    if return_sorted: return inds, [s[i] for i in inds]
    return inds
def alp2num(c,cap=False): return ord(c)-97 if not cap else ord(c)-65
def num2alp(i,cap=False): return chr(i+97) if not cap else chr(i+65)
def matmat(A,B):
    K,N,M=len(B),len(A),len(B[0])
    return [[sum([(A[i][k]*B[k][j]) for k in range(K)]) for j in range(M)] for i in range(N)]
def matvec(M,v):
    N,size=len(v),len(M)
    return [sum([M[i][j]*v[j] for j in range(N)]) for i in range(size)]
def T(M):
    n,m=len(M),len(M[0])
    return [[M[j][i] for j in range(n)] for i in range(m)]
def binr(x): return bin(x)[2:]
def bitcount(x): #xは64bit整数
    x= x - ((x >> 1) & 0x5555555555555555)
    x= (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333)
    x= (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f 
    x+= (x >> 8); x+= (x >> 16); x+= (x >> 32) 
    return x & 0x7f
import random
class rh:#base,max_n=ありうる文字の最大長,convertを指定すること
    def __init__(self,base,max_n):#baseとmaxnを指定すること。baseは偶数(modが奇数)
        self.mod=random.randrange(1<<54-1,1<<55-1,2)#奇数、衝突させられないよう乱数で生成
        self.base=int(base*0.5+0.5)*2#偶数,英小文字なら26とか
        self.max_n=max_n
        self.pows1=[1]*(max_n+1)
        cur1=1
        for i in range(1,max_n+1):
            cur1=cur1*base%self.mod
            self.pows1[i]=cur1

    def convert(self,c): return alp2num(c,False)#大文字の場合Trueにする
    
    def get(self, s):#特定の文字のhash. O(|s|)
        n=len(s)
        mod=self.mod
        si=[self.convert(ss) for ss in s]
        h1=0
        for i in range(n):h1=(h1+si[i]*self.pows1[n-1-i])%mod
        return h1
    
    def get_roll(self, s, k, uroboros=False):#ローリングハッシュ,sの各文字を始点とした長さkの部分文字のhash値をすべて得る,O(|s|)
        #uroboros: trueの場合文字sを循環させ、n個のハッシュ値を得る。 falseの場合n-k+1個
        n=len(s)
        maxitr=n-k+1
        if uroboros: maxitr=n
    
        si=[self.convert(ss) for ss in s]
        mod=self.mod
        h1=0
        for i in range(k):h1=(h1+si[i%n]*self.pows1[k-1-i])%mod
        hs=[0]*maxitr
        hs[0]=h1
        mbase1=self.pows1[k]
        base=self.base
        
        for i in range(1,maxitr): 
            front=si[i-1];back=si[(i+k-1)%n]
            h1=(h1*base-front*mbase1+back)%mod
            hs[i]=h1
        return hs

def main():
    mod = 1000000007
    #w.sort(key=itemgetter(1),reverse=True)  #二個目の要素で降順並び替え

    N = int(input())
    mod=1000000007
    mod2=999999937

    #N, K = map(int, input().split())
    #A = tuple(map(int, input().split())) #1行ベクトル
    L=["" for _ in range(N)]
    ll=[0]*N
    for i in range(N):
        s=input()
        ls=len(s)
        ll[i]=ls
        L[i]=s

    #S = tuple(tuple(map(int, input().split())) for i in range(N)) #改行行列

    inds=argsort(ll)
    d=Counter()
    ans=0
    base=27

    for im in inds:
        
        s=L[im]

        ls=len(s)
        cur=0
        cur2=0
        se=Counter(s)
        #printe(se)
        for i in range(ls):
            for a,val in se.items():
                if val:
                    ai=alp2num(a)
                    ans+=d[(i+1,(cur*base+ai)%mod,(cur2*base+ai)%mod2)]
                    
            si=s[-1-i]
            sin=alp2num(si)
            cur=(cur*base+sin)%mod
            cur2=(cur2*base+sin)%mod2

            se[si]-=1

        d[(ls,cur,cur2)]+=1

    print(ans)
            





if __name__ == "__main__":
    main()