分析
对于前缀问题,考虑 T r i e Trie T r i e 树转化为树上问题
把所有字符串 a d d add a d d 进 T r i e Trie T r i e 树后记录字符串结尾的位置
贪心
的去取字符串
思路是
从下向上
用 s z [ ] sz[] s z [ ] 记录每个结点拥有的子树个数
对于一个结点 u u u
记录结点 u u u 的子树 v v v 的 s z [ v ] sz[v] s z [ v ] ,存入 v e c t o r vector v e c t o r 中
当 s z [ u ] > k sz[u] > k s z [ u ] > k 时
从大到小的取走 v e c t o r vector v e c t o r 中的 s z [ v ] , r e s + + sz[v] , res++ s z [ v ] , r e s + +
为什么每次只能删除一个子树 v v v 呢?
因为对于 u u u 的另一个子树 v ′ v^{\prime} v ′ , 删除 v v v 的前缀并不是 v ′ v^{\prime} v ′ 的前缀
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 int n,k;int son[300005 ][26 ];int ed[300005 ],sz[300005 ];int res,idx;void add (string &s) { int p = 0 ; for (auto c:s){ if (!son[p][c-'a' ]) son[p][c-'a' ] = ++idx; p = son[p][c-'a' ]; } ed[p]++; } void dfs (int u) { sz[u] = ed[u]; vector<int > t; for (char c = 'a' ; c<= 'z' ;c++){ int v = son[u][c-'a' ]; if (v){ dfs (v); sz[u] += sz[v]; t.push_back (sz[v]); } } sort (t.begin (),t.end ()); while (sz[u] > k){ res++; sz[u] -= t.back (); t.pop_back (); } } signed main () { cin >> n >> k; for (int i = 1 ;i <= n;i++){ string s;cin >> s; add (s); } dfs (0 ); cout << res + (sz[0 ] > 0 ) << endl; return 0 ; }