[题目链接]
https://codeforces.com/contest/204/problem/E
[算法]
首先构建广义后缀自动机
对于自动机上的每个节点 , 维护一棵平衡树存储所有它所匹配的字符串编号
可以通过启发式合并得到
计算答案时 , 我们枚举每个右端点 , 当当前集合大小 < K时 , 不断走向link节点
时间复杂度 : O(NlogN)
[代码]
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int N = 2e5 + 10; const int ALPHA = 26; #define rint register int int n , k; string st[N]; struct Suffix_Automaton { int sz , last; int father[N] , depth[N] , child[N][ALPHA] , cnt[N]; set< int > s[N]; vector< int > a[N]; Suffix_Automaton() { sz = 1; last = 1; } inline int new_node(int dep) { depth[++sz] = dep; father[sz] = 0; memset(child[sz] , 0 , sizeof(child[sz])); return sz; } inline void extend(int ch , int col) { int np = child[last][ch]; if (np) { if (depth[np] == depth[last] + 1) { s[np].insert(col); last = np; return; } else { int nq = new_node(depth[last] + 1); father[nq] = father[np]; father[np] = nq; memcpy(child[nq] , child[np] , sizeof(child[nq])); for (int p = last; child[p][ch] == np; p = father[p]) child[p][ch] = nq; s[nq].insert(col); last = nq; return; } } else { np = new_node(depth[last] + 1); int p = last; for (; child[p][ch] == 0; p = father[p]) child[p][ch] = np; if (child[p][ch] == np) { father[np] = 1; s[np].insert(col); last = np; return; } else { int q = child[p][ch]; if (depth[q] == depth[p] + 1) { father[np] = q; s[np].insert(col); last = np; return; } else { int nq = new_node(depth[p] + 1); father[nq] = father[q]; father[np] = father[q] = nq; memcpy(child[nq] , child[q] , sizeof(child[nq])); for (; child[p][ch] == q; p = father[p]) child[p][ch] = nq; s[np].insert(col); last = np; } } } } inline void insert(string s , int col) { last = 1; for (rint i = 0; i < (int)s.size(); ++i) extend(s[i] - 'a' , col); } inline void dfs(int u) { for (unsigned i = 0; i < a[u].size(); ++i) { int v = a[u][i]; dfs(v); if ((int)s[u].size() < (int)s[v].size()) swap(s[u] , s[v]); for (set< int > :: iterator it = s[v].begin(); it != s[v].end(); ++it) s[u].insert(*it); } cnt[u] = (int)s[u].size(); } inline void work() { for (rint i = 2; i <= sz; ++i) a[father[i]].push_back(i); dfs(1); } } SAM; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } int main() { read(n); read(k); for (rint i = 1; i <= n; ++i) { cin >> st[i]; SAM.insert(st[i] , i); } SAM.work(); for (rint i = 1; i <= n; ++i) { int now = 1; ll ans = 0; for (rint j = 0; j < st[i].size(); ++j) { now = SAM.child[now][st[i][j] - 'a']; while (now != 1 && SAM.cnt[now] < k) now = SAM.father[now]; ans += (ll)SAM.depth[now]; } printf("%lld " , ans); } printf("\n"); return 0; }