题目大意

题意

分析

对于前缀问题,考虑 TrieTrie 树转化为树上问题

把所有字符串 addaddTrieTrie 树后记录字符串结尾的位置

贪心的去取字符串

思路是

从下向上sz[]sz[] 记录每个结点拥有的子树个数

对于一个结点 uu

记录结点 uu 的子树 vvsz[v]sz[v],存入 vectorvector

sz[u]>ksz[u] > k

从大到小的取走 vectorvector 中的 sz[v],res++sz[v] , res++

为什么每次只能删除一个子树 vv 呢?

因为对于 uu 的另一个子树 vv^{\prime}, 删除 vv 的前缀并不是 vv^{\prime} 的前缀

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;
}