题目大意:给出n个旧单词,要从这n个旧单词中构造新单词。构造条件是 S = Sa + Sb,其中Sa为某个旧单词的非空前缀,Sb为某个单词的非空后缀。求所有的新单词和旧单词中有多少个不同的单词。

思路:将所有单词建成一棵字典树,再将所有单词反转并建成一棵字典树。则第一棵树的结点个数即为不同前缀的数量,第二棵树的结点个数为不同后缀的数量。如果不算重复,取两者的乘积即为新单词的数量。

接下来考虑重复的情况。什么样子会重复呢?假设第一棵树中某个前缀为a1a2a3...X,第二棵树中某个后缀为Xb1b2b3...。那么这就一定会有重复,也就是前缀的末字符和后缀的首字符相同时会重复。考虑a1a2a3...Xb1b2b3...,这个X可能出现在前缀里,也可能出现在后缀里,这也就是多算了一种情况。考虑一般情况,假设第一棵树中某个前缀为a1a2a3...XXX..X(一共m个X),第二棵树中某个后缀为XXX...Xb1b2b3...(一共n个X),那么这两个串组成的串a1a2a3XX...Xb1b2b3...中X的数目有m+n+1种可能(0~m+n),而前缀中X的数目有(m+1)种可能(0~m个),同理后缀中X的数目(n+1)种可能,因此我们在实际计算中一共多算了(m+1)*(n+1) - (m+n+1) = m*n次,即前缀中X的数目与后缀中X数目的乘积。

那么,我们只要分别求出两棵树中每个字符的出现次数并减去它们的乘积即可(这是用了加法乘法原理,假设第一棵树中末尾为X的前缀共有3个,分别含a1、a2、a3个X;第二棵树中开头为X的后缀为3个,分别含b1、b2、b3个X,则一共重复算了a1*b1+a1*b2+a1*b3+a2*b1+a2*b2+a2*b3+a3*b1+a3*b2+a3*b3=(a1+a2+a3)*(b1+b2+b3)次)。这里要注意,只统计深度大于1的结点,因为我们要保证前后缀均非空(如前缀X与后缀Xb就不会有重复,因为第一个的X必须要选)。最后,再加上长度为1的旧单词即可,因为我们构造单词时不会造出长度为1的单词。

#include<cstdio>
#include<cstring>
#include<string>
#include<cctype>
#include<iostream>
#include<set>
#include<map>
#include<cmath>
#include<sstream>
#include<vector>
#include<stack>
#include<queue>
#include<algorithm>
#define fin freopen("a.txt","r",stdin)
#define fout freopen("a.txt","w",stdout)
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const int inf = 1e9 + ;
const int maxnode = 4e5 + ;
const int sigma_size = ;
const int maxn = + ;
char s[];
int vis[sigma_size]; struct Tree
{
int ch[maxnode][sigma_size];
int val[maxnode];
int cnt[sigma_size];
int sz;
int idx(char c) { return c - 'a'; }
void init() { memset(ch[], , sizeof ch[]); sz = ; memset(cnt, , sizeof cnt); } void insert(char *s)
{
int n = strlen(s), u = ;
for(int i = ; i < n; i++)
{
int c = idx(s[i]);
if(!ch[u][c])
{
memset(ch[sz], , sizeof ch[sz]);
val[sz] = ;
ch[u][c] = sz++;
if(i) cnt[c]++;
}
u = ch[u][c]; }
val[u] = ;
} }Pre, Suf; int main()
{ int n;
while(scanf("%d", &n) == )
{
Pre.init(); Suf.init();
memset(vis, , sizeof vis);
for(int i = ; i <= n; i++)
{
scanf("%s", s);
Pre.insert(s);
int len = strlen(s);
reverse(s, s+len);
Suf.insert(s);
if(len == ) vis[s[]-'a'] = ;
}
LL ans = LL(Pre.sz-)*LL(Suf.sz-);
for(int i = ; i < sigma_size; i++)
ans -= (LL)Pre.cnt[i] * LL(Suf.cnt[i]);
for(int i = ; i < sigma_size; i++)
if(vis[i]) ++ans;
cout << ans << endl;
}
return ;
}

UVA5913 Dictionary Sizes(字典树)(转载)的更多相关文章

  1. uva 1519 - Dictionary Size(字典树)

    题目链接:uva 1519 - Dictionary Size 题目大意:给出n个字符串组成的字典.如今要加入新的单词,从已有单词中选出非空前缀和非空后缀,组成新单词. 问说能组成多少个单词. 解题思 ...

  2. [转载]字典树(trie树)、后缀树

    (1)字典树(Trie树) Trie是个简单但实用的数据结构,通常用于实现字典查询.我们做即时响应用户输入的AJAX搜索框时,就是Trie开始.本质上,Trie是一颗存储多个字符串的树.相邻节点间的边 ...

  3. 萌新笔记——用KMP算法与Trie字典树实现屏蔽敏感词(UTF-8编码)

    前几天写好了字典,又刚好重温了KMP算法,恰逢遇到朋友吐槽最近被和谐的词越来越多了,于是突发奇想,想要自己实现一下敏感词屏蔽. 基本敏感词的屏蔽说起来很简单,只要把字符串中的敏感词替换成"* ...

  4. [LeetCode] Implement Trie (Prefix Tree) 实现字典树(前缀树)

    Implement a trie with insert, search, and startsWith methods. Note:You may assume that all inputs ar ...

  5. 萌新笔记——C++里创建 Trie字典树(中文词典)(一)(插入、遍历)

    萌新做词典第一篇,做得不好,还请指正,谢谢大佬! 写了一个词典,用到了Trie字典树. 写这个词典的目的,一个是为了压缩一些数据,另一个是为了尝试搜索提示,就像在谷歌搜索的时候,打出某个关键字,会提示 ...

  6. 字典树 - A Poet Computer

    The ACM team is working on an AI project called (Eih Eye Three) that allows computers to write poems ...

  7. poj 2503:Babelfish(字典树,经典题,字典翻译)

    Babelfish Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 30816   Accepted: 13283 Descr ...

  8. hdu 1247:Hat’s Words(字典树,经典题)

    Hat’s Words Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total ...

  9. hdu 1075:What Are You Talking About(字典树,经典题,字典翻译)

    What Are You Talking About Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/204800 K ...

随机推荐

  1. docker-管理数据

    管理Docker中的数据 默认情况下,在容器内创建的所有文件都存储在可写容器层中.这意味着: 当该容器不再运行时,数据不会持久存在,如果另一个进程需要,则可能很难从容器中获取数据. 容器的可写层紧密耦 ...

  2. 高斯消去法解线性方程组(MPI)

    用一上午的时间,用MPI编写了高斯消去法解线性方程组.这次只是针对单线程负责一个线程方程的求解,对于超大规模的方程组,需要按行分块,后面会在这个基础上进行修改.总结一下这次遇到的问题: (1)MPI_ ...

  3. 如何在Go项目中输出版本信息?

    我们经常在使用CLI工具的时候,都会有这样的参数输出: ``` ➜ ~ docker version Client: Docker Engine - Community Version: 18.09. ...

  4. Web及网络基础学习(一)

    ---恢复内容开始--- 2019.10.16 1.TCP.IP分层  应用层.网络层.传输层.数据链路层 2.各层讲解 应用层 决定了向用户提供应用服务时通信的活动.例如FTP(File Trans ...

  5. VS2019菜单栏没有团队选项解决方法

    新安装了Visual Studio 2019结果菜单栏没有“团队”菜单,导致没办法连接TFS服务器,查了下网上也并没有对应解决方法(甚至遇见这个问题的都没有/笑哭,所以这个方法写出来也大概没什么用) ...

  6. Flutter使用SingleTickerProviderStateMixin报错

    最近在学习开发Flutter应用项目,在创建tabbar和tabview后,进行网络请求后显示顶部tab标签,设置TabController,并使class类实现SingleTickerProvide ...

  7. 引用dll出现的问题:发生一个或多个错误,引用无效或不支持该引用

    获取到新的项目后,然后FineUI就出现黄色的标志,肯定是不可以用的,需要重新引用下. 然后我就开始重新引用下,就出现下面的问题: 因为是购买的UI,一开始我怀疑是引用的版本不一样呢,其实都不是 只需 ...

  8. 安装SQL的时候,设置用户权限失败

    在安装sql的时候,遇到一个问题: 在查看报表明细中,提示: 就是这三个: 首先确保你是使用管理员用户安装的,如果还不行,运行 secpol.msc 进入本地安全策略 把自己的用户名加入进来就好了.

  9. Elasticsearch系列---结构化搜索

    概要 结构化搜索针对日期.时间.数字等结构化数据的搜索,它们有自己的格式,我们可以对它们进行范围,比较大小等逻辑操作,这些逻辑操作得到的结果非黑即白,要么符合条件在结果集里,要么不符合条件在结果集之外 ...

  10. 【JDK1.8】 Java小白的源码学习系列:HashMap

    目录 Java小白的源码学习系列:HashMap 官方文档解读 基本数据结构 基本源码解读 基本成员变量 构造器 巧妙的tableSizeFor put方法 巧妙的hash方法 JDK1.8的putV ...