【bzoj1174】[Balkan2007]Toponyms

zz:https://www.cnblogs.com/GXZlegend/p/7134233.html

题目描述

给你一个字符集合,你从其中找出一些字符串出来. 希望你找出来的这些字符串的最长公共前缀*字符串的总个数最大化.

输入

第一行给出数字N.N在[2,1000000] 下面N行描述这些字符串,长度不超过20000 。保证输入文件不超过10MB

输出

a single line with an integer representing the maximal level of complexity Lc(T).

样例输入

7
Jora de Sus
Orhei
Jora de Mijloc
Joreni
Jora de Jos
Japca
Orheiul Vechi

样例输出

24

题解

Trie树

很显然建立Trie树,用 每个节点的深度*对应字符串个数 更新答案。

但是本题卡空间只有128M,不能使用普通的Trie树存边方式,必须使用邻接表(链式前向星)存边。

所以每次插入时扫一遍,看能否扫到该字符,并决定是否添加新边。

时间复杂度O(53len),卡卡常数可以过。另外数组大小已实测。

#include<bits/stdc++.h>
#define RG register
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=5e6+10;
int n,cnt,tot,ans;
int head[N],si[N];

struct nk
{
	char c;
	int nex,to;
}e[N];

inline void add(int x,int y,char c)
{
	e[++cnt].nex=head[x];
	head[x]=cnt;
	e[cnt].to=y;
	e[cnt].c=c;
}

int main()
{
	int n;
	scanf("%d",&n);
	tot=1;
	while(n--)
	{
		char ch=getchar();
		while(ch=='\n') ch=getchar();
		for (int j=1,q=1;ch!='\n';ch=getchar(),q++)
		{//从根节点开始搜 
			int p=0;
			for (int k=head[j];k;k=e[k].nex)//遍历每一个节点 
				if(ch==e[k].c)
				{
					p=e[k].to;
					break;
				}
				//如果存在 

			if(!p) add(j,p=++tot,ch);
			j=p,si[j]++,ans=max(ans,q*si[j]);
		}
	}
	
	printf("%d\n",ans);
	
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/cutemush/p/12520726.html