白書上的第二個字典樹,這個題目需要用到字典樹的一種新的寫法,用到了在分支的時候採用的左兒子、右兄弟的寫法,非常的實用的寫法,也是非常的新穎的。這個題難度還是蠻高的,數據要用LL,不然會溢出,因爲字符集比較大啊!
可參考博客:http://www.cnblogs.com/372465774y/archive/2013/04/10/3012071.html
http://blog.csdn.net/mobius_strip/article/details/27260579
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxnode=4000010;
const int maxn=1050;
int n;
long long sum;
char ch[maxnode];
int son[maxnode],bro[maxnode];
int val[maxnode]; //每個i爲根的val[i]爲其葉子結點總數目
int sz;
void init()
{
sum=0;
sz=1;
val[0]=son[0]=bro[0]=0;
}
int idx(char c)
{
return c-'a';
}
void insert(char *s)
{
int u=0,n=strlen(s);
val[0]++;
for(int i=0;i<=n;i++)
{
bool f=false;int v;
for(v=son[u];v!=0;v=bro[v])
{
if(ch[v]==s[i])
{
f=true;
break;
}
}
if(!f)
{
v=sz++;
val[v]=0;
ch[v]=s[i];
bro[v]=son[u];
son[u]=v;
son[v]=0;
}
u=v;
val[u]++;
}
}
void dfs(int depth,int u)
{
if(son[u]==0)
sum+=val[u]*(val[u]-1)*depth;
else
{
int s=0;
for(int v=son[u];v!=0;v=bro[v])
{
s+=val[v]*(val[u]-val[v]);
}
sum+=s/2*(2*depth+1);
for(int v=son[u];v!=0;v=bro[v])
dfs(depth+1,v);
}
}
long long counts()
{
dfs(0,0);
return sum;
}
int main()
{
int kase=1;
char tmp[maxn];
while(scanf("%d",&n)!=EOF)
{
if(n==0)
break;
init();
for(int i=0;i<n;i++)
{
scanf("%s",tmp);
insert(tmp);
}
printf("Case %d: %lld\n",kase++,counts());
}
return 0;
}