[codeforces965E]Short Code

给定n个互不相同的字符串,可以将每个字符串缩短为其非空前缀,保持唯一性,求最小总长度。通过建立 Trie 数据结构并进行深度优先搜索来解决此问题。

time limit per test : 1 second
memory limit per test : 256 megabytes

Arkady’s code contains nnn variables. Each variable has a unique name consisting of lowercase English letters only. One day Arkady decided to shorten his code.

He wants to replace each variable name with its non-empty prefix so that these new names are still unique (however, a new name of some variable can coincide with some old name of another or same variable). Among such possibilities he wants to find the way with the smallest possible total length of the new names.

A string aaa is a prefix of a string b if you can delete some (possibly none) characters from the end of bbb and obtain aaa .Please find this minimum possible total length of new names.
Input

The first line contains a single integer n(1≤n≤105)n(1≤n≤10^5)n(1n105) — the number of variables.

The next nnn lines contain variable names, one per line. Each name is non-empty and contains only lowercase English letters. The total length of these strings is not greater than 10510^5105. The variable names are distinct.

Output

Print a single integer — the minimum possible total length of new variable names.

Examples

Input

3
codeforces
codehorses
code

Output

6

Input

5
abba
abb
ab
aa
aacada

Output

11

Input

3
telegram
digital
resistance

Output

3

Note

In the first example one of the best options is to shorten the names in the given order as "cod""cod""cod", "co""co""co", "c""c""c".

In the second example we can shorten the last name to "aac""aac""aac" and the first name to "a""a""a" without changing the other names.

题意:
给定nnn个互不相同的字符串,你可以把一个字符串变成他的一个非空前缀,问:使得这些字符串仍然互不相同的最小字符串总长度是多少。

题解:
你先建一个trie,每个节点放一个multiset,表示前缀为当前节点的字符串们的长度集合。但是预处理的时候只需要放在每个字符串的结束节点就行了,反正后面合并的时候都能求。
那么我们从root开始dfs。首先,如果当前节点不是root并且当前节点不是某个字符串的结尾节点,那么以当前节点为前缀的字符串中可以有一个可以截断成当前节点所代表的长度。将所有的儿子节点的信息存入当前节点,然后取一个最长的截断即可。记得用启发式合并。

#include<bits/stdc++.h>
#define LiangJiaJun main
using namespace std;
int ch[100004][34],sz;
int n,m;
char s[100004];
multiset<int>lv[100004];
void INS(char *s){
     int l=strlen(s+1);
     int u=0;
     for(int i=1;i<=l;i++){
         int to=s[i]-'a';
         if(!ch[u][to]){
            lv[sz].clear();
            ch[u][to]=sz++;
         }
         u=ch[u][to];
     }
     lv[u].insert(l);
}

void dfs(int x,int dep){
     bool ok=(x&&lv[x].size()==0);
     for(int i=0;i<26;i++){
         int to=ch[x][i];
         if(!to)continue;
         dfs(to,dep+1);
         if(lv[x].size()<lv[to].size())swap(lv[x],lv[to]);
         for(int v:lv[to])lv[x].insert(v);
         lv[to].clear();
     }
     if(ok){
        lv[x].erase(--lv[x].end());
        lv[x].insert(dep);
     }
}
int LiangJiaJun(){
    scanf("%d",&n);
    sz=1;
    memset(ch[0],0,sizeof(ch[0]));
    for(int i=1;i<=n;i++){
        scanf("%s",s+1);
        INS(s);
    }
    dfs(0,0);
    int ans=0;
    for(int v:lv[0])ans+=v;
    printf("%d\n",ans);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值