CF965E Short Code

思路、实现

第一眼看到前缀,果断使用字典树。

逐个插入字符串进行读入,并在字符串末尾打结束标记。

struct Trie
{
    int next[30],dep;
    bool end;
}T[MAXN];

void insert(string s)
{
    int x=0;
    for(int i=0;i<s.size();i++)
    {
        int t=s[i]-'a';
        if(!T[x].next[t])
        {
            T[x].next[t]=++tot;
            T[tot].dep=T[x].dep+1;
        }
        x=T[x].next[t];
    }
    T[x].end=true;
}

然后一种贪心策略就出现了:在 Trie 上进行 dfs,扫到结束记号就向树根移动。于是我们就会愉快地发现,这样连样例都过不了。只要构造一棵 Trie,使它先进行 dfs 的子树中结束记号较少,而后进行 dfs 的子树中结束记号较多,这个策略就不可能得出正解。(估计也只有我这个蒟蒻还会用这个策略调半天。)

不过通过这个错误的策略,我们也可以有所启发:我们应当优先将深度最大的结束标记移到树根附近。而这可以通过多重集合或优先队列进行维护。

Code

//insert() 函数末尾需添加 q[x].push(T[x].dep);

priority_queue<int>q[MAXN];

void dfs(int x)
{
    for(int i=0;i<30;i++)
    {
        int v=T[x].next[i];
        if(!v)continue;
        dfs(v);
        while(!q[v].empty())
        {
            q[x].push(q[v].top());
            q[v].pop();
        }
    }
    if(!T[x].end&&x)
    {
        q[x].pop();
        q[x].push(T[x].dep);
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        string s;
        cin>>s;
        insert(s);
    }
    dfs(0);
    int ans=0;
    while(!q[0].empty())
    {
        ans+=q[0].top();
        q[0].pop();
    }
    cout<<ans;
    return 0;
}
posted @ 2023-08-11 14:43  H2ptimize  阅读(17)  评论(0)    收藏  举报  来源