题目传送
用Trie把所有单词合起来,插入一次就统计一次这个单词和已插入的单词比较的次数。也就是相同部分前缀长度*2+1.但是注意两个完全相同的单词比如说a a需要比4次,因为最后的结束符号也是一样的,还有就是左儿子右兄弟表示法,好好学习QAQ。
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1000+10;
const int maxnode=4000000+10;
typedef long long ll;
struct Trienode{
char ch;
int cnt,val;
Trienode *lc,*next;
Trienode(){
lc=next=NULL;
val=cnt=ch=0;
}
};
struct Trie{
Trienode *root;
Trie(){
root=new Trienode();
}
inline void clear(){
root=new Trienode();
}
inline ll insert(Trienode *p,char *s,int v){
ll ret=0;
int n=strlen(s);
for(int i=0;i<n;i++)
{
int x=0;
Trienode *k=p->lc,*wh=NULL;
for(;k;k=k->next)
{
if(k->ch==s[i])wh=k;
else x+=k->cnt;
}
k=wh;
if(!k)
{
k=new Trienode();
k->next=p->lc;
p->lc=k;
k->ch=s[i];
}
if(x) ret=ret+(i*2+1)*x;
if(i==n-1)
{
ret=ret+((i+1)*2+1)*k->cnt;
if(k->val) ret+=k->val;
}
else if(k->val) ret=ret+(2*(i+1)+1)*k->val;
k->cnt++;
p=k;
}
p->val+=v;
return ret;
}
}trie;
int kase=0,n;
char s[maxn];
void solve()
{
trie.clear();
ll ans=0;
for(int i=1;i<=n;i++)
{
scanf("%s",s);
ans+=trie.insert(trie.root,s,1);
}
printf("Case %d: %lld\n",++kase,ans);
return ;
}
int main()
{
while(scanf("%d",&n)==1&&n) solve();
return 0;
}