如果用常规发放存储字典树,那么空间需要2亿多int,肯定会爆空间,所以用左耳子-右兄弟的方法存字典树。
然后当节点是叶子结点的时候那么比较次数就是tot[u]*(tot[u]-1)*dep,如果非叶子结点,那么统计他的儿子节点与兄弟节点的个数然后相乘最后除2再乘比较次数就是到目前节点的比较次数了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define ss(x) scanf("%d",&x)
const int maxnode=4000*1000+5;
struct Trie{
int head[maxnode];
int next[maxnode];
char ch[maxnode];
int tot[maxnode];
int sz;
long long ans;
void clear() {sz=1;head[0]=next[0]=tot[0]=0;}
void insert(char *s)
{
int n=(int)strlen(s);int u=0,v;
tot[0]++;
rep(i,0,n){
bool find=false;
for(v=head[u];v!=0;v=next[v])
if(ch[v]==s[i]) {find=true;break;}
if(!find)
{
v=sz++;
tot[v]=0;
ch[v]=s[i];
next[v]=head[u];
head[u]=v;
head[v]=0;
}
u=v;
tot[u]++;
}
}
void dfs(int u,int dep)
{
if(head[u]==0) ans+=tot[u]*(tot[u]-1)*dep;
else{
long long sum=0;
for(int v=head[u];v!=0;v=next[v])
sum+=tot[v]*(tot[u]-tot[v]);
ans+=sum/2*(2*dep+1);
for(int v=head[u];v!=0;v=next[v])
dfs(v,dep+1);
}
}
long long count()
{
ans=0;
dfs(0,0);
return ans;
}
};
Trie trie;
char word[1000+5];
int main()
{
int n,kase=0;
while(true)
{
ss(n);if(n==0) break;
trie.clear();
rep(i,1,n) {scanf("%s",word);trie.insert(word);}
printf("Case %d: %lld\n",++kase,trie.count());
}
}