题目链接:https://vjudge.net/problem/UVA-11488
题意:给定n个字符串,从n个字符串中选出若干个组成字符串集合S。定义P(S)为集合S中所有串的最长公共前缀长度与S中字符串个数的乘积。求一个集合S,使得P(S)最大。
思路:首先将所有串建成一颗Trie树,然后遍历整个Trie树。当遍历到某个结点u时,从起始根节点往下到u构成了一个前缀,以这个为前缀的字符串个数即为u及其子树中单词结点的个数,这两个的乘积便是一个答案。边遍历边统计答案即可。
#include<cstdio>
#include<cstring>
#include<string>
#include<cctype>
#include<iostream>
#include<set>
#include<map>
#include<cmath>
#include<sstream>
#include<vector>
#include<stack>
#include<queue>
#include<algorithm>
#define fin freopen("a.txt","r",stdin)
#define fout freopen("a.txt","w",stdout)
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const int inf = 1e9 + 10;
const int maxnode = 1e7 + 10;
const int sigma_size = 2;
const int maxn = 35;
LL res;
struct Tree
{
int ch[maxnode][sigma_size];
int val[maxnode];
int depth[maxnode], size[maxnode];
int sz;
int idx(char c) { return c - '0'; }
void init() { memset(ch[0], 0, sizeof ch[0]); sz = 1; }
void insert(char *s)
{
int n = strlen(s), u = 0;
for(int i = 0; i < n; i++)
{
int c = idx(s[i]);
if(!ch[u][c])
{
memset(ch[sz], 0, sizeof ch[sz]);
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
depth[u] = i+1;
}
val[u]++;
}
int Find(int u)
{
int ans = 0;
for(int i = 0; i < 2; i++)
{
int c = ch[u][i];
if(c) ans += Find(c);
}
if(val[u]) ans += val[u];
res = max(res, (LL)depth[u] * ans);
return size[u] = ans;
}
}tree;
int main()
{
int T, n;
char s[205];
scanf("%d", &T);
while(T--)
{
tree.init();
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
scanf("%s", s);
tree.insert(s);
}
res = 0;
tree.Find(0);
cout << res << endl;
}
return 0;
}