码迷,mamicode.com
首页 > 其他好文 > 详细

UVA 11732 strcmp() Anyone (Trie+链表)

时间:2015-09-09 09:38:21      阅读:125      评论:0      收藏:0      [点我收藏+]

标签:

先两两比较,比较次数是两者相同的最长前缀长度*2+1,比较特殊的情况是两者完全相同时候比较次数是单词长度*2+2,

两个单词‘末尾\0‘和‘\0‘比较一次,s尾部‘\0‘和循环内‘\0‘比较一次。

因此,对于一个单词,只要知道和它某个相同的最长前缀的单词数就可以计算出方案数了。

用tire,记录一颗子树上的结点数cnt[u]和在某个结点终止的单词数val[u](处理特殊情况)。

因为字符集比较大,可能会有较大的空间浪费,所以用一个链式的结构保存子节点。(查找子节点的时候效率会低一些)。

如果插完了以后再统计的话一个前缀会被算2次,要除以2。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxnds = 4001*1000+5;

char ch[maxnds];
int cnt[maxnds];
int son[maxnds],bro[maxnds];
int val[maxnds];
int nds;
void init()
{
    nds = 1; cnt[0] = son[0] = val[0] = 0;
}

ll add(char *s)
{
    ll ret = 0;
    int u = 0,v,i;
    for(i = 0; s[i]; i++){
        for(v = son[u]; v; v = bro[v]){
            if(ch[v] == s[i]) break;
        }
        if(!v){ //没找到,插到链表头
            bro[nds] = son[u];
            ch[nds] = s[i];
            val[nds] = cnt[nds] = son[nds] = 0;
            v = son[u] = nds++;
        }
        ret += (cnt[u]-cnt[v])*(i<<1|1);
        cnt[u]++;
        u = v;
    }
    if(val[u]) ret += val[u]*((i+1)<<1);
    ret += (cnt[u]-val[u])*(i<<1|1);
    cnt[u]++; val[u]++;
    return ret;
}

char str[1500];
int main()
{
    //freopen("in.txt","r",stdin);
    int N,kas = 0;
    while(scanf("%d\n",&N),N){
        ll ans = 0;
        init();
        while(N--){
            gets(str);
            ans += add(str);
        }
        printf("Case %d: %lld\n",++kas,ans);
    }
    return 0;
}

 

UVA 11732 strcmp() Anyone (Trie+链表)

标签:

原文地址:http://www.cnblogs.com/jerryRey/p/4793597.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!