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