题目链接:http://codeforces.com/contest/965/problem/E
首先建立字典树,然后问题转换为有n个人站在一棵树上,每个人可以往根的位置移动任意步,但是不能同时有两个人站在一个点上,我们可以dp来做,dp[i]表示,以i为根的子树最好的结果,对于每个每次合并子树,如果根节点没有人,则把所有子树中深度最大的那个人放到根上即可。可以用multiset维护,每次启发式合并。
代码:
#include<bits/stdc++.h> using namespace std; const int MAXN=1e5+5; struct Tri { int ch[MAXN][26]; bool vis[MAXN]; int tot,root; void init() { memset(ch,-1,sizeof(ch)); memset(vis,false,sizeof(vis)); tot=0;root=0; } void insert(string x) { int u=root; for(int i=0;i<x.size();i++) { int nxt=x[i]-'a'; if(ch[u][nxt]==-1) ch[u][nxt]=++tot; u=ch[u][nxt]; } vis[u]=true; } }T; string s; multiset<int> merge(multiset<int> a,multiset<int> b) { if(a.size()<b.size()) swap(a,b); for(auto x:b) { a.insert(x); } return a; } multiset<int> dfs(int now,int cur) { multiset<int> ret; if(T.vis[now]) { ret.insert(cur); } for(int i=0;i<26;i++) { if(T.ch[now][i]==-1) continue; ret=merge(ret,dfs(T.ch[now][i],cur+1)); } if(cur!=0&&!T.vis[now]) { ret.erase(prev(ret.end())); ret.insert(cur); } return ret; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int n; scanf("%d",&n); T.init(); for(int i=1;i<=n;i++) { cin>>s; T.insert(s); } multiset<int> ans=dfs(T.root,0); int res=0; for(auto x:ans) { res+=x; } printf("%d\n",res); return 0; }