解题思路:
首先我们可以发现:
1.若两个字符串A、B不相等,且它们的公共前缀为S,则它们的比较次数为:2 * len(S) + 1;
2.若两个字符串相等,设为A,则它们的比较次数为 2 * ( len(A) + 1 ) //注意考虑结束符'\0'
那么我们可以建立前缀树,在向前缀树中插入字符串的过程中,如果遇到分叉结点则需要进行比较。
特别注意:"aaaa","aa"以及"aaaa","aaaa"的情况
具体做法:
Trie维护每个结点的val和flag,其中val表示经过每个结点的字符串个数,flag表示是否是分叉结点。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cctype> 5 #include <algorithm> 6 using namespace std; 7 8 const int maxnode = 4000*1000 + 10; 9 const int _size = 63; 10 long long ans; 11 12 struct Trie { 13 int ch[maxnode][_size]; 14 int val[maxnode]; 15 int flag[maxnode]; 16 int sz; 17 Trie() { 18 sz = 1; 19 memset(ch[0], 0, sizeof (ch[0])); 20 } 21 int idx(int c) { 22 if(c == '\0') return 62; 23 else if(isdigit(c)) return c - '0'; 24 else if(c >= 'A' && c <= 'Z') return c - 'A' + 10; 25 else return c - 'a' + 36; 26 } 27 28 void insert(char *s) { 29 int u = 0, n = strlen(s); 30 val[u]++; 31 int i; 32 for(i = 0; i <= n; i++) { 33 int c = idx(s[i]); 34 if(!ch[u][c]) { 35 memset(ch[sz], 0, sizeof (ch[sz])); 36 ch[u][c] = sz++; 37 val[ch[u][c]] = 1; 38 if(val[u] > 1){ 39 flag[u] = 1; 40 ans += (2*i+1) * (val[u]-val[ch[u][c]]); 41 } 42 } 43 else { 44 val[ch[u][c]]++; 45 if(flag[u]) ans += (2*i+1) * (val[u]-val[ch[u][c]]); 46 } 47 u = ch[u][c]; 48 49 } 50 if(val[u] > 1) { 51 flag[u] = 1; 52 ans += (2*i) * (val[u]-1); 53 } 54 } 55 56 void clear() { 57 sz = 1; 58 memset(val, 0 , sizeof val); 59 memset(ch[0], 0, sizeof (ch[0])); 60 memset(flag, 0, sizeof flag); 61 } 62 }; 63 64 char s[1010]; 65 Trie T; 66 67 int main(int argc, const char * argv[]) { 68 69 int n; 70 int kase = 1; 71 while(scanf("%d", &n) == 1 && n) { 72 T.clear(); 73 ans = 0; 74 for(int i = 0; i < n; i++) { 75 scanf("%s", s); 76 T.insert(s); 77 } 78 79 printf("Case %d: %lld\n", kase++, ans); 80 } 81 return 0; 82 }