题意:给出多个字符串,两两配对,求总配对次数。
思路:如果两个字符串一样,ans=strlen(字符串)*2+2,如果不同,ans=公共前缀长度*2+1;用左儿子右兄弟建字典树。插入一个字符计算一次。
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <cstdlib> 5 #include <iostream> 6 #include <algorithm> 7 #include <queue> 8 #include <map> 9 #include <vector> 10 using namespace std; 11 const int maxn=111; 12 const int maxnode=4000010; 13 typedef long long LL; 14 15 struct trie 16 { 17 int son[maxnode]; 18 int bro[maxnode]; 19 char ch[maxnode]; 20 LL ans; 21 int num[maxnode]; 22 int sizee; 23 24 void init() 25 { 26 sizee=1; 27 son[0]=bro[0]=num[0]=0; 28 ans=0; 29 } 30 31 void insertt(char *s) 32 { 33 int len=strlen(s); 34 int p,u=0; 35 for(int i=0; i<=len; i++) 36 { 37 for(p=son[u]; p; p=bro[p]) 38 { 39 if(ch[p]==s[i]) 40 break; 41 } 42 if(!p) 43 { 44 p=sizee++; 45 ch[p]=s[i]; 46 bro[p]=son[u]; 47 son[p]=0; 48 num[p]=0; 49 son[u]=p;//p为u的左儿子 50 } 51 ans+=(num[u]-num[p])*(2*i+1);//前缀长度为i,当前这个字母的比较次数为num[u]-num[p] 52 if(i==len)//匹配到最后一个字符,还需与当前这个字母相同的字符比较,而且之前减去num[p]次 53 { 54 ans+=num[p]*(2*i+2); 55 num[p]++; 56 } 57 num[u]++; 58 u=p; 59 } 60 } 61 } T; 62 63 int main() 64 { 65 int n,cas=1; 66 char str[4010]; 67 while(~scanf("%d",&n)&&n) 68 { 69 T.init(); 70 for(int i=0; i<n; i++) 71 { 72 scanf("%s",str); 73 T.insertt(str); 74 } 75 printf("Case %d: %lld ",cas++,T.ans); 76 } 77 return 0; 78 }