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 <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <algorithm> #include <vector> using namespace std; int read() { int x = 0, f = 1; char c = getchar(); while(!isdigit(c)) { if(c == '-') f = -1; c = getchar(); } while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); } return x * f; } #define maxn 5000010 #define LL long long int n, rt, ToT, m, val[maxn], head[maxn], nxt[maxn], to[maxn]; char ec[maxn]; LL ans; void insert() { int u = rt; val[u]++; char C = getchar(); for(int i = 0; C != ' '; i++, C = getchar()) { int v = -1; for(int e = head[u]; e; e = nxt[e]) if(ec[e] == C) //看是否能找到一个C这样一个子结点 { v = to[e]; break; } if(v < 0) //如果没找到则新加一个 { to[++m] = ++ToT; ec[m] = C; nxt[m] = head[u]; head[u] = m; v = ToT; } val[u = v]++; ans = max(ans, (LL)val[u] * (i + 1)); } return ; } int main() { n = read(); rt = ToT = 1; for(int i = 1; i <= n; i++) insert(); printf("%lld ", ans); return 0; }