zoukankan      html  css  js  c++  java
  • 题解-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;
    }
    
  • 相关阅读:
    P1182 数列分段 Section II 题解
    P3853 路标设置题解
    二分模板
    P2678 跳石头题解
    P2440 木材加工题解
    P1024 一元三次方程求解题解
    快速下载vscode的方法
    P1824 进击的奶牛题解
    P1873 砍树题解
    用户登录之asp.net cookie的写入、读取与操作
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/14901180.html
Copyright © 2011-2022 走看看