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

浙公网安备 33010602011771号