描述:给定N个字符串,求这些字符串的最长公共前缀长度与字符串的个数的乘积的最大值。
范围:1<=N<=1000000 每个字符串长度小于20000
样例:
7
Jora de Sus
Orhei
Jora de Mijloc
Joreni
Jora de Jos
Japca
Orhejul Vechi
方法一:裸的字典树
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 struct letter{ 5 char d;//节点存的字符 6 int son,bro;//左孩子和右兄弟,都是节点编号 7 int cnt;//此节点的孩子个数 8 }; 9 10 char line[30000]; 11 int N,best=0,gs=0; 12 letter tr[10000001]; 13 14 void insert(char s[]){ 15 int len=strlen(s);//字符串长度,也是字符串在树中的深度 16 int now=0;//当前节点 17 18 for(int i=0;i<len;i++){//i表示深度,深度为0的是root,并不是某字符 19 tr[now].cnt++; 20 21 if(tr[now].cnt*i>best)//每一个节点都尝试更新答案 22 best=tr[now].cnt*i; 23 24 if(tr[now].son==0){//这个节点没有左孩子 25 tr[++gs].d=s[i];//插入点 26 tr[now].son=gs;//让gs为now的左孩子 27 now=gs;//更行当前节点 28 } 29 else{ 30 now=tr[now].son; 31 while(tr[now].d!=s[i]&&tr[now].bro>0){//找到合适的节点插入 32 now=tr[now].bro; 33 } 34 if(tr[now].d!=s[i]){ 35 tr[++gs].d=s[i]; 36 tr[now].bro=gs; 37 now=gs; 38 } 39 40 } 41 } 42 tr[now].cnt++; 43 44 if(tr[now].cnt*len>best){//这个更新容易漏掉 45 best=tr[now].cnt*len; 46 } 47 48 49 } 50 51 int main(){ 52 scanf("%d",&N); 53 for(int i=1;i<=N;i++){ 54 gets(line); 55 insert(line); 56 } 57 cout<<best; 58 return 0; 59 }