constint Root = 1; int Tree[MAXN][30]= {0}; int Father[MAXN]= {0}; int Len[MAXN]= {0}, Size[MAXN]= {0}; int Belong[MAXN]= {0}; int last = Root, nodes = 1; voidAppend(int c, int bel){ int fa = last, p = ++ nodes; last = p; Len[p] = Len[fa] + 1; while (fa && ! Tree[fa][c]) Tree[fa][c] = p, fa = Father[fa]; if (! fa) Father[p] = 1; else { int x = Tree[fa][c]; if (Len[x] == Len[fa] + 1) Father[p] = x; else { int np = ++ nodes; Len[np] = Len[fa] + 1, Father[np] = Father[x]; Father[p] = Father[x] = np; memcpy (Tree[np], Tree[x], sizeof (Tree[x])); while (fa && Tree[fa][c] == x) Tree[fa][c] = np, fa = Father[fa]; } } } int Topo[MAXN]; int W[MAXN]= {0}; int buck[MAXN]= {0}; voidMerge(){ for (int i = 1; i <= N; i ++) { int n = Str[i].size(); int p = Root; for (int j = 0; j < n; j ++) { p = Tree[p][Str[i][j] - 'a']; int fa = p; while (fa && Belong[fa] != i) { Size[fa] ++; Belong[fa] = i; fa = Father[fa]; } } } for (int i = 1; i <= nodes; i ++) buck[Len[i]] ++; for (int i = 1; i <= nodes; i ++) buck[i] += buck[i - 1]; for (int i = nodes; i >= 1; i --) Topo[buck[Len[i]] --] = i; for (int i = 1; i <= nodes; i ++) if (Size[i] >= K) W[i] = Len[i] - Len[Father[i]]; for (int i = 1; i <= nodes; i ++) W[Topo[i]] += W[Father[Topo[i]]]; }
LL Answer[MAXN >> 2]= {0};
intmain(){ scanf ("%d%d", & N, & K); for (int i = 1; i <= N; i ++) { cin >> Str[i]; int n = Str[i].size(); last = Root; for (int j = 0; j < n; j ++) Append (Str[i][j] - 'a', i); } Merge (); for (int i = 1; i <= N; i ++) { int n = Str[i].size(); int p = Root; for (int j = 0; j < n; j ++) p = Tree[p][Str[i][j] - 'a'], Answer[i] += W[p]; } for (int i = 1; i <= N; i ++) { if (i > 1) putchar (' '); printf ("%lld", Answer[i]); } puts ("");