• codeforces 965E Trie+multiset


    E. Short Code
    time limit per test
    1 second
    memory limit per test
    256 megabytes
    input
    standard input
    output
    standard output

    Arkady's code contains nn 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 aa is a prefix of a string bb if you can delete some (possibly none) characters from the end of bb and obtain aa.

    Please find this minimum possible total length of new names.

    Input

    The first line contains a single integer nn (1n1051≤n≤105) — the number of variables.

    The next nn 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 105105. The variable names are distinct.

    Output

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

    Examples
    input
    Copy
    3
    codeforces
    codehorses
    code
    output
    Copy
    6
    input
    Copy
    5
    abba
    abb
    ab
    aa
    aacada
    output
    Copy
    11
    input
    Copy
    3
    telegram
    digital
    resistance
    output
    Copy
    3
    Note

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

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

    题意:给出很多字符串(1e5),总长度不超过1e5.

    每个字符串用其某前缀代替,代替后要保证每个字符串互不相同。

    求代替后最短的总距离。

    题解:

    做法非常巧妙和套路

    建个Trie树,每个节点维护深度和一个multiset用于存储深度(当前取得字符串前缀的长度)(也可以用priority_queue,这种做法明天补上)

    初始时,叶节点的multiset存储该节点的深度,这个初始状态就是最差的情况,即每个字符串都保留原串,下面会在合并的时候进行统计和优化。

    然后从根节点开始dfs,dfs回溯段合并子节点的multiset,合并之后,去掉multiset中的最大值,插入当前节点深度(意义就是将当前最长的前缀替换成当前节点所代表的前缀,这样贪心一定是最优的)。

    最后遍历根节点的multiset就可以得到答案。

    合并的复杂度是这样的,根据主定理,就是mlogm

    ,multiset的操作的复杂度是logm,总复杂度是m*(logm)^2

    合并之后一定要把子节点的multiset清空,不然会MLE。

     1 /*
     2 ◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇
     3 ◇◇◇◇◇◇◆◆◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◆◇◇◇◇◇◇◇◇◇
     4 ◇◇◇◇◇◇◆◆◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◆◆◇◇◇◇◇◇◇◇◇
     5 ◇◇◇◇◇◇◇◆◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◆◇◇◇◇◇◇◇◇◇
     6 ◇◇◇◇◇◇◇◆◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◆◇◆◆◆◇◇◇◇◇
     7 ◇◇◇◇◇◇◇◆◇◇◇◇◇◇◇◇◇◇◇◇◆◆◆◆◆◇◇◇◇◇◇◇◇◇◇◆◆◆◆◆◇◇◇◇◇
     8 ◇◇◇◇◇◇◇◆◇◇◇◇◇◇◇◇◇◇◇◇◆◆◆◆◆◇◇◇◇◇◇◇◇◇◇◆◆◇◆◆◇◇◇◇◇
     9 ◇◇◇◇◇◇◇◆◇◇◇◇◇◇◇◇◇◇◇◇◇◇◆◆◇◇◇◇◇◇◇◇◇◇◇◆◇◇◇◆◇◇◇◇◇
    10 ◇◇◇◇◇◇◇◆◇◇◇◇◇◇◇◇◇◇◇◇◇◆◆◇◇◇◇◇◇◇◇◇◇◇◇◆◇◇◇◆◇◇◇◇◇
    11 ◇◇◇◇◇◇◇◆◇◇◇◇◇◇◇◇◇◇◇◇◆◆◆◇◆◇◇◇◇◇◇◇◇◇◇◆◇◇◇◆◇◇◇◇◇
    12 ◇◇◇◇◇◇◆◆◆◆◇◇◇◇◇◇◇◇◇◇◆◆◆◆◆◇◇◇◇◇◇◇◇◇◆◆◆◇◆◆◆◇◇◇◇
    13 ◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇
    14 ◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇
    15 ◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇
    16 ◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇◇
    17 */
    18 #include<iostream>
    19 #include<cstdio>
    20 #include<cstring>
    21 #include<ctime>
    22 #include<cstdlib>
    23 #include<algorithm>
    24 #include<cmath>
    25 #include<string>
    26 #include<set>
    27 #include<vector>
    28 using namespace std;
    29 int read(){
    30     int xx=0,ff=1;char ch=getchar();
    31     while(ch>'9'||ch<'0'){if(ch=='-')ff=-1;ch=getchar();}
    32     while(ch>='0'&&ch<='9'){xx=xx*10+ch-'0';ch=getchar();}
    33     return xx*ff;
    34 }
    35 const int maxn=100010;
    36 int N;
    37 char str[maxn];
    38 struct Trie{
    39     int lin[26];
    40     int depth;
    41     multiset<int>s;
    42 }T[maxn];
    43 int cnt=0;
    44 void insert(int depth,int root){
    45     if(!str[depth]){
    46         T[root].s.insert(T[root].depth);
    47         return;
    48     }
    49     if(!T[root].lin[str[depth]-'a']){
    50         T[root].lin[str[depth]-'a']=++cnt;
    51         T[cnt].depth=T[root].depth+1;
    52     }
    53     insert(depth+1,T[root].lin[str[depth]-'a']);
    54 }
    55 void trav(int x){
    56     bool flag=x&&T[x].s.empty();
    57     for(int i=0;i<26;i++)
    58         if(T[x].lin[i]){
    59             trav(T[x].lin[i]);
    60             if(T[x].s.size()<T[T[x].lin[i]].s.size())
    61                 swap(T[x].s,T[T[x].lin[i]].s);
    62             for(multiset<int>::iterator it=T[T[x].lin[i]].s.begin();it!=T[T[x].lin[i]].s.end();it++)
    63                 T[x].s.insert(*it);
    64             T[T[x].lin[i]].s.clear();
    65         }
    66     if(flag){
    67         T[x].s.erase(--T[x].s.end());
    68         T[x].s.insert(T[x].depth);
    69     }
    70 }
    71 int main(){
    72     //freopen("in","r",stdin);
    73     N=read();
    74     for(int i=1;i<=N;i++){
    75         gets(str);
    76         insert(0,0);
    77     }
    78     trav(0);
    79     long long ans=0;
    80     for(multiset<int>::iterator it=T[0].s.begin();it!=T[0].s.end();it++)
    81         ans+=(*it);
    82     printf("%I64d
    ",ans);
    83     return 0;
    84 }
    View Code
  • 相关阅读:
    GO语言的进阶之路-Golang字符串处理以及文件操作
    将本地的代码推送到公网的github账号去
    GO语言的进阶之路-go的程序结构以及包简介
    Linux操作系统原理
    Linux安装-kickstart无人值守安装
    LVM逻辑卷管理
    Liunx软Raid实现
    parted分区工具用法
    高级Linux运维工程师必备技能(扫盲篇)
    H3C配置FTP服务器
  • 原文地址:https://www.cnblogs.com/lzhAFO/p/8965194.html
Copyright © 2020-2023  润新知