裸Trie也能过,卡一下内存
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#define LL long long
#define INF 0x3f3f3f3f
#define mod 20071027
const int maxn = 4000000+5;
using namespace std;
char s[1005];
int n;
LL ans;
struct Trie{
int ch[maxn][64];
int val[maxn];
int sum[maxn][64];
int sz;
Trie(){ memset(ch[0], 0, sizeof(ch[0])); sz = 1;}
int idx(char ch) {
if('a' <= ch && ch <= 'z')
return ch - 'a';
else if('A' <= ch && ch <= 'Z')
return ch - 'A' + 26;
else if('0' <= ch && ch <= '9')
return ch - '0' + 52;
return ch - '\0' + 62;
}
void init(){
memset(ch[0], 0, sizeof(ch[0]));
memset(val, 0, sizeof(val));//总的节点数
memset(sum, 0, sizeof(sum));//当前这种的节点数
sz = 1;
}
void insert(char *s){
int u = 0, n = (int)strlen(s);
for(int i=0; i<=n; i++){
int c = idx(s[i]);
if(!ch[u][c]){
memset(ch[sz], 0, sizeof(ch[sz]));
ch[u][c] = sz++;
}
if(i == n){
ans += 2*(i+1)*sum[u][c];
}
ans += 2*i*(val[u]-sum[u][c]) + val[u]-sum[u][c];
val[u]++;
sum[u][c]++;
u = ch[u][c];
}
}
}tree;
int main(){
int kases = 1;
while(scanf("%d",&n) == 1 && n){
ans = 0;
tree.init();
for(int i=0; i<n; i++){
scanf("%s",s);
tree.insert(s);
//cout << ans << endl;
}
printf("Case %d: %lld\n",kases++,ans);
}
}
左兄弟右儿子没有注释光看代码看的我头疼。。
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#define LL long long
#define INF 0x3f3f3f3f
#define mod 20071027
const int maxn = 4000 * 1000 + 5;
using namespace std;
char s[1005];
int n;
LL ans;
struct Trie{
int son[maxn];
int bro[maxn];
int val[maxn];
char ch[maxn];
int sz;
Trie(){sz = 1; ch[0] = 0; val[0] = bro[0] = son[0] = 0;}
void init(){sz = 1; ch[0] = 0;val[0] = bro[0] = son[0] = 0;}
void insert(char *s){
int n = (int)strlen(s), u = 0, j;
for(int i=0; i<=n; i++){
for(j=son[u]; j; j=bro[j]){//从儿子开始遍历
if(ch[j] == s[i]) break;
}
if(!j){
j = sz++;//构造新的节点
ch[j] = s[i];//将该节点字符赋值
bro[j] = son[u];//将上一个儿子作为该节点的兄弟
son[j] = val[j] = 0;//因为是新开的节点,所以儿子和个数都是0
son[u] = j;//原本儿子变为兄弟,新儿子即为j
}
ans += (val[u]-val[j])*(2*i+1);//val[u] - val[j]是兄弟的总数
if(n == i){//如果遍历到最后了即终止符号
ans += val[j]*(2*i+2);//避免相同字符串
val[j]++;//因为不会再往下了所以当前位置需要+1,否则会在下一层+1
}
val[u]++;//每层有多少个节点
u = j;
}
}
}tree;
int main(){
int kases = 1;
while(scanf("%d",&n) == 1 && n){
ans = 0;
tree.init();
for(int i=0; i<n; i++){
scanf("%s",s);
tree.insert(s);
}
printf("Case %d: %lld\n",kases++,ans);
}
}