• 题解 UVA11488 【Hyper Prefix Sets】


    题目链接
    首先,我们由输入数据多个字符串,以及求公共前缀,很容易想到这道题是(Trie)的应用

    我们把(Trie)树建好,然后在上面跑一个树形(dp)即可。

    即以(dp(u,dis))表示以(u)为根的子树,(u)深度为(dis)时的答案

    由题目定义很容易想到,(dp(u,dis) = max{dis * tot[u],dp(v,dis + 1)})

    (tot[u])为以(u)为根的子树的叶子节点个数(即以根节点到(u)这段作为公共前缀,具有这段公共前缀的字符串数量为(tot[u]))

    于是我们可以想到一个初级代码:

    #include <bits/stdc++.h>
    using namespace std;
    struct Trie{
        static const int maxnode = 100100;
        static const int sigma_size = 2;
        int ch[maxnode][sigma_size];
        int val[maxnode];
        int sz;
        inline void init(){sz = 1;memset(ch[0],0,sizeof(ch[0]));memset(val,0,sizeof(val));}
        Trie(){sz = 1;memset(ch[0],0,sizeof(ch[0]));memset(val,0,sizeof(val));}
        inline int idx(char c){return c - '0';}
        inline void insert(const string &s){
            int u = 0,n = s.size();
            for(int i = 0;i < n;i++){
                int c = idx(s[i]);
                if(!ch[u][c]){
                    memset(ch[sz],0,sizeof(ch[sz]));
                    val[sz] = 0;
                    ch[u][c] = sz++;        
                }
                u = ch[u][c];
            }
            val[u]++;
        }
        inline int tot(int u){
            int ret = val[u];
            for(int c = 0;c < sigma_size;c++)
                if(ch[u][c])ret += tot(ch[u][c]);
            return ret;
        }
        inline int dfs(int u,int dis){
            int ret = dis * tot(u);
            for(int c = 0;c < sigma_size;c++)
                if(ch[u][c])ret = max(ret,dfs(ch[u][c],dis + 1));
            return ret;
        }
    }tt;
    string ss;
    int T,n;
    inline void solve(){
        tt.init();  	
        cin >> n;
        for(int i = 1;i <= n;i++){
            cin >> ss;
            tt.insert(ss);
        }
        printf("%d
    ",tt.dfs(0,0));
    }
    int main(){
        ios::sync_with_stdio(false);
        cin >> T;
        while(T--)
            solve();
        return 0;
    }
    
    

    这份代码跑了160ms,不会超时,但我们还是可以考虑优化。

    每次(dp)都算一次(tot),时间复杂度原地爆炸(虽然数据H2O无伤大雅)。

    于是

    我们可以在建(Trie)树的时候将(tot)数组给算出来.

    平常建(Trie)树是给叶子节点赋权值,在这道题里,我们把建树时经过的每一个点权值都(+1),这样每个节点的权值就是以这个节点为根的子树的叶子节点个数了

    代码:

    #include <bits/stdc++.h>//懒得打了,大家最好别用万能头文件
    using namespace std;
    struct Trie{
        static const int maxnode = 100100;//最大节点数
        static const int sigma_size = 2;//字符集大小
        int ch[maxnode][sigma_size];//儿子数组
        int val[maxnode];//节点附加权值,即转移方程的tot数组
        int sz;//当前节点总数
        inline void init(){sz = 1;memset(ch[0],0,sizeof(ch[0]));memset(val,0,sizeof(val));}//初始化函数
        Trie(){sz = 1;memset(ch[0],0,sizeof(ch[0]));memset(val,0,sizeof(val));}
        inline int idx(char c){return c - '0';}
        inline void insert(const string &s){//插入字符串,传引用避免拷贝开销
            int u = 0,n = s.size();
            for(int i = 0;i < n;i++){
                int c = idx(s[i]);
                if(!ch[u][c]){
                    memset(ch[sz],0,sizeof(ch[sz]));
                    val[sz] = 0;
                    ch[u][c] = sz++;        
                }
                u = ch[u][c];
                val[u]++;//这里即上文所说的统计子树节点个数
            }
        }
        inline int dfs(int u,int dis){//最终答案
            int ret = val[u] * dis;
            for(int c = 0;c < sigma_size;c++)
                if(ch[u][c])
                    ret = max(ret,dfs(ch[u][c],dis + 1));
            return ret;
        }
    }tt;
    string ss;
    int T,n;
    inline void solve(){//多组数据求解
        tt.init(); 
        cin >> n;
        for(int i = 1;i <= n;i++){
            cin >> ss;
            tt.insert(ss);
        }
        printf("%d
    ",tt.dfs(0,0));
    }
    int main(){
        ios::sync_with_stdio(false);
        cin >> T;
        while(T--)
            solve();
        return 0;
    }
    
  • 相关阅读:
    报名用户主题看板
    有效线索主题看板 阿善有用 清洗转换具体怎么做
    意向客户主题看板 阿善看到 阿善用到 拉链表
    数据库建模 全量表导入
    git 阿善有用
    IDEA+git+码云
    Cloudera Manager的基本使用 阿善没用
    cloudera manager报错解决方案
    java-多态简述及实例
    java-简述接口及实例
  • 原文地址:https://www.cnblogs.com/colazcy/p/11514703.html
Copyright © 2020-2023  润新知