• 题解-UVA11732 "strcmp()" Anyone?


    如果按照题意模拟的话是肯定会超时的(题目都好心告诉你了),考虑优化。

    我们发现对于两个串我们只用求它们的最长公共前缀即可。

    如果将所有串建一棵(trie),那最长公共前缀就对应到它们的结束节点在(trie)树上的(lca)。所以我们建好(trie)后只用遍历一遍所有节点看看它是几个串的(lca)即可。

    其实只需要一波数学推导即可。

    对于一条边(u->v),我们统计出子树(u)(v)分别有多少结束标记(sum),然后对应以(u)为lca的串就增加(sum[v] imes (sum[u] - sum[v]))

    然后我们发现这是成对出现的所以要除以(2)

    最后加上上述值乘上根到当前节点的距离乘(2)(1)即可。

    如果当前节点是多个串的结尾,那还要考虑这些串互相的贡献。其实也很好考虑。

    (End[x])代表节点(x)有多少串在这结尾,则答案会加上((End[x] imes (End[x] - 1) / 2) * ((dis + 1) imes 2))

    但是写完之后交上去发现错了。

    可参考hack数据:

    2
    
    app
    
    apple
    

    原因是直接(sum[v] imes (sum[u] - sum[v]))并不是所有乘 (2),与结尾刚好到(x)的串其实就只有一次,所以要再额外考虑。

    Code:

    #include <bits/stdc++.h>
    using namespace std;
    int trie[4000010][62], tot = 1;
    char s[1010];
    long long End[4000010], sum[4000010];
    int n;
    long long ans;
    int num;
    int f(char ch) {
    	if (isdigit(ch)) {
    		return ch - '0';
    	}
    	if ('a' <= ch && ch <= 'z') {
    		return ch - 'a' + 10;
    	}
    	return ch - 'A' + 36;
    }
    void dfs(int x, int dis) {
    	long long cnt = 0;
    	for (int i = 0; i < 62; i++) {
    		if (trie[x][i]) {
    			cnt += sum[trie[x][i]] * (sum[x] - sum[trie[x][i]] - End[x]);
    			cnt += End[x] * sum[trie[x][i]] * 2;
    			dfs(trie[x][i], dis + 1);
    			trie[x][i] = 0;
    		}
    	}
    	cnt >>= 1;
    	ans += cnt * ((dis << 1) + 1);
    	ans += (End[x] * (End[x] - 1) >> 1) * ((dis + 1) << 1);
    	End[x] = 0;
    	sum[x] = 0;
    }
    int main() {
    	while (scanf("%d", &n) != EOF && n) {
    		num++;
    		tot = 1;
    		for (int i = 1, len, p; i <= n; i++) {
    			scanf("%s", s + 1);
    			len = strlen(s + 1);
    			p = 1;
    			for (int j = 1; j <= len; j++) {
    				sum[p]++;
    				if (!trie[p][f(s[j])]) trie[p][f(s[j])] = ++tot;
    				p = trie[p][f(s[j])];
    			}
    			sum[p]++;
    			End[p]++;
    		}
    		ans = 0;
    		dfs(1, 0);
    		printf("Case %d: %lld
    ", num, ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    gethostbyname() 用域名或主机名获取IP地址
    recv, recvfrom, recvmsg 从套接口接收一个消息
    献给初学者:谈谈如何学习Linux操作系统
    Linux 文件处理 之扫描目录 DIR
    Python 使用sys模块
    struct dirent和DIR结构体
    职场人必读的文字只花10分钟影响你一辈子!
    信号量与线程互斥锁的区别
    send/sendto/sendmsg函数解析
    互联网常见Open API文档资源
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/14901180.html
Copyright © 2020-2023  润新知