Codeforces Round #476 (Div. 2) [Thanks, Telegram!] E. Short Code(dp)

题目链接: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;
}

猜你喜欢

转载自blog.csdn.net/sinat_32872703/article/details/80111228