UVA11732 "strcmp()" Anyone?

题目链接:https://vjudge.net/problem/UVA-11732

知识点:  字典树、儿子兄弟表示法

解题思路:

  首先,为每一个字符的末尾添加一个 '$',因为有一种特殊情况:如果两个字符串(假设长度为 len )完全相同,则比较次数是 (2 len + 2) ,因为两个字符串末尾的 '\0' 也是相同的。

  用字典树维护字符串集。当插入字符串 \(S\) 中的一个字符时,算出字典树已有的字符串中跟 \(S\) 直到上一个字符都是相同的字符串数 \(last\),以及插入这个字符后仍然跟 \(S\) 相同的字符串数 \(news\),则对答案的贡献即为 \((news \times 2 + last - news)\).

AC代码:

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 typedef long long ll;
 5 const int maxn = 4000004;
 6 
 7 char ch[maxn]; //保存结点字符
 8 int son[maxn], bro[maxn];    //son是链表头, bro[u]表示u的下一个兄弟结点
 9 int nds; //nds是下一个可以分配的结点
10 int cnt[maxn];  //cnt[x]表示经过结点x的字符串数
11 
12 ll add(char *str) {
13     int len = strlen(str);
14     str[len] = '$', str[len + 1] = '\0';
15     ll ret = 0;
16     //***********************************************
17     //儿子-兄弟表示法(其实就是结合了链表的字典树,目的是节省空间)
18     int now = 0;
19     int last = cnt[now];
20     for (int i = 0; i <= len; i++) {
21         int v;
22         for (v = son[now]; v; v = bro[v]) {
23             if (ch[v] == str[i])   break;
24         }
25         if (!v) {
26             bro[nds] = son[now];
27             ch[nds] = str[i];
28             cnt[nds] = son[nds] = 0;
29             v = son[now] = nds++;
30         }
31         now = v;
32         //************************************************
33         int news = cnt[now];
34         ret += news * 2;
35         ret += (last - news);
36         last = cnt[now];
37         cnt[now]++;
38     }
39     return ret;
40 }
41 char str[4005];
42 int main() {
43     //    freopen("in.txt","r",stdin);
44     int N, kase = 1;
45     while (scanf("%d", &N) == 1 && N) {
46         nds = 1, cnt[0] = son[0] = bro[0] = 0; //初始化
47         ll ans = 0;
48         while (N--) {
49             scanf("%s", str);
50             ans += add(str);
51             cnt[0]++;
52         }
53         printf("Case %d: %lld\n", kase++, ans);
54     }
55     return 0;
56 }

 

转载于:https://www.cnblogs.com/Blogggggg/p/8553194.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值