Trie树的一道水题,根据系统的strcmp函数,求比较次数。
就是给你n个单词,让他们两两比较,要求他们运用strcmp时,进行比较的次数。
根据题目数据量的范围,肯定不能用简单模拟,然后就想到比较时建Trie树,关键是考虑怎么计数,例如than和that它们比较的次数就是7次,因为他们是在a之后出现不同,就是要记录比较结束的位置,来进行计算即可,那么我们就来一个val数组代表计数器就好了,代表经过该节点的单词个数。
需要注意的是两个单词完全相同的处理,所以加上了一个isEnd数组。
#include "stdio.h"
#include "string.h"
#include <iostream>
using namespace std;
#define Mem(a, b) memset(a, b, sizeof(a))
const int maxNode = 4000005;
int val[maxNode];
int ch[maxNode][62];
int isEnd[maxNode];
struct Trie{
int sz;
long long ans;
Trie(){
sz = 1;
Mem(ch, 0);
Mem(val, 0);
Mem(isEnd, 0);
ans = 0;
}
int idx(char s){
if(s >= '0' && s <= '9'){
return s - '0';
}
else if(s >= 'A' && s <= 'Z'){
return 10 + s - 'A';
}
else{
return 36 + s - 'a';
}
}
void insert(char *s){
int u = 0, n = strlen(s);
for(int i = 0; i < n; i ++){
int v = idx(s[i]);
if(ch[u][v] == 0){
ans += val[u] * (2 * i + 1);
ch[u][v] = sz ++;
}
else{
ans += (val[u] - val[ch[u][v]]) * (2 * i + 1);
}
val[u] ++;
u = ch[u][v];
}
ans += (isEnd[u] * 2 * (n + 1) );
ans += (val[u] - isEnd[u]) * (2 * n + 1);
val[u] ++;
isEnd[u] ++;
}
long long query(){
return ans;
}
};
int cnt;
int nCase;
char sS[1005];
void solve(){
Trie tmp;
for(int i = 0; i < cnt; i ++){
cin>>sS;
tmp.insert(sS);
}
cout<<tmp.query()<<endl;
}
int main(){
nCase = 0;
while(cin>>cnt){
if(cnt == 0) break;
printf("Case %d: ", ++nCase);
solve();
}
return 0;
}