当前位置: 首页 > news >正文

2017ACM暑期多校联合训练 - Team 6 1001 HDU 6096 String (字符串处理 字典树)...

题目链接

Problem Description
Bob has a dictionary with N words in it.
Now there is a list of words in which the middle part of the word has continuous letters disappeared. The middle part does not include the first and last character.
We only know the prefix and suffix of each word, and the number of characters missing is uncertain, it could be 0. But the prefix and suffix of each word can not overlap.
For each word in the list, Bob wants to determine which word is in the dictionary by prefix and suffix.
There are probably many answers. You just have to figure out how many words may be the answer.

Input
The first line of the input gives the number of test cases T; T test cases follow.
Each test case contains two integer N and Q, The number of words in the dictionary, and the number of words in the list.
Next N line, each line has a string Wi, represents the ith word in the dictionary (0<|Wi|≤100000)
Next Q line, each line has two string Pi , Si, represents the prefix and suffix of the ith word in the list (0<|Pi|,|Si|≤100000,0<|Pi|+|Si|≤100000)
All of the above characters are lowercase letters.
The dictionary does not contain the same words.

Limits
T ≤ 5
0 < N, Q ≤ 100000
∑ Si + Pi ≤ 500000
∑ Wi ≤ 500000

Output

For each test case, output Q lines, an integer per line, represents the answer to each word in the list.

Sample Input
1
4 4
aba
cde
acdefa
cdef
a a
cd ef
ac a
ce f

Sample Output
2
1
1
0

题意:
给出n个字符串,q个查询,每个查询包含A、B两个字符串,问在给定的n个字符串中,有多少个字符串满足前缀是A,后缀是B且前缀后缀没有重叠部分

分析:
对查询离线处理,给定的字符串保存下来,而对查询的前缀后缀建立字典树,建树过程如下,假设有ac ef这种查询情况:

先将ef翻转过来使得查询变为ac fe, 之后再加一个特殊字符将前缀于后缀连接起来变为ac#fe,对ac#fe建立字典树,并在这个字符串的结尾处设置一个值,这个值为当前查询前后缀的下标k(即第几个查询),如果查询的前缀后缀都相同的,取第一个出现的就好了。

然后是对给定的字符串查询,就是查询每个字符串对查询的贡献,假设有ac ef的查询,有给定的字符串acdef,在字典树上匹配的时候有先有0->a,发现没有a#,继续,然后0->a->c发现ac#有,那么就开始将acdef的字符串反过来匹配了,变成0->a->c->#->f->e 因为f没有值,到达e的时候发现e这处节点有值k,那么就是ans[k]++。

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
typedef long long ll;
const int maxn = 6e5 + 10;
const int INF = 1e9 + 10;
const int mod = 1e9 + 7;
using namespace std;

int val[maxn], sz;
int ch[maxn][27];
char str[maxn];
char s[maxn];
int n,T,q;
int len[maxn], ans[maxn];
int nxt[maxn];

int __insert(int st, int l, int r, int v, int flag)///根节点,左右区间,表示前后缀而且只需要在后缀记录数目,正逆序标记
{
    int u = st, t = abs(r - l) + 1;
    for(int i = l; t--; i += flag)///循环遍历整个前缀或者后缀
    {
        int c = s[i] - 'a';
        if(!ch[u][c])
        {
            memset(ch[sz], 0, sizeof ch[sz]);
            val[sz] = 0;
            ch[u][c] = sz++;
        }
        u = ch[u][c];
    }
    if(v)///表示当前插入的这个是后缀的情况
    {
        if(val[u] == 0)  val[u] = v;
        else nxt[v] = val[u];///如果有多个的后缀是以同一个字母结尾的,都取同一个就好了
    }
    return u;
}

void query(int L, int R)///查询一个单词
{
    int u = 0;
    for(int i = L; i <= R; i++)
    {
        int c = str[i] - 'a';
        if(!ch[u][c]) return ;///压根就没有这个前缀的单词
        u = ch[u][c];
        if(!ch[u][26]) continue;///找到这个前缀了
        int st = ch[u][26];
        for(int j = R; j > i; j--)反过来找后缀
        {
            int k = str[j] - 'a';
            st = ch[st][k];
            if(!st) break;
            if(val[st]) ans[val[st]]++;
        }
    }
}

int main()
{
    scanf("%d", &T);
    while(T--)
    {
        sz = 1;
        memset(ch[0], 0, sizeof ch[0]);
        val[0] = 0;
        scanf("%d %d", &n, &q);
        for(int i = 1; i <= q; i++) nxt[i] = i;
        int num = 0;
        for(int i = 0; i < n; i++)
        {
            scanf("%s", str + num);
            len[i] = strlen(str + num);
            num += len[i];
        }
        for(int i = 1; i <= q; i++)
        {
            ans[i] = 0;
            scanf("%s", s);
            int l1 = strlen(s);
            s[l1++] = 'a' + 26;
            scanf("%s", s + l1);
            int l2 = strlen(s + l1);
            int node = __insert(0, 0, l1 - 1, 0, 1);
            __insert(node, l2 + l1 - 1, l1, i, -1);
        }
        num = 0;
        for(int i = 0; i < n; i++)
        {
            query(num, num + len[i] - 1);
            num += len[i];
        }
        for(int i = 1; i <= q; i++)
        {
            printf("%d\n", ans[nxt[i]]);
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/cmmdc/p/7360140.html

相关文章:

  • python三级菜单
  • jquery ajax添加元素事件无效,each,on函数参考
  • js 判断确切判断Array和Object
  • s7day1学习记录
  • Eclipse配置文件描述
  • C#6.0VISUALSTUDIO 2015 C#入门经典 第7版pdf
  • Navicat Premium连接各种数据库
  • 8.19-星期五
  • 二叉树转换成森林amp;森林变成二叉树
  • JS学习一
  • Python 2 和 Python 3的继承
  • hdu 6153 A Secret(KMP)
  • Tomcat入门
  • 表单,正则
  • 第4阶段——制作根文件系统之分析init进程(2)
  • [ JavaScript ] 数据结构与算法 —— 链表
  • Android 控件背景颜色处理
  • conda常用的命令
  • css选择器
  • Fastjson的基本使用方法大全
  • Git同步原始仓库到Fork仓库中
  • input的行数自动增减
  • JavaScript工作原理(五):深入了解WebSockets,HTTP/2和SSE,以及如何选择
  • java中的hashCode
  • Koa2 之文件上传下载
  • leetcode讲解--894. All Possible Full Binary Trees
  • web标准化(下)
  • 创建一个Struts2项目maven 方式
  • 排序算法学习笔记
  • 如何使用 OAuth 2.0 将 LinkedIn 集成入 iOS 应用
  • 设计模式 开闭原则
  • 小程序button引导用户授权
  • 一些关于Rust在2019年的思考
  • #我与Java虚拟机的故事#连载18:JAVA成长之路
  • $.extend({},旧的,新的);合并对象,后面的覆盖前面的
  • %3cscript放入php,跟bWAPP学WEB安全(PHP代码)--XSS跨站脚本攻击
  • (Matlab)遗传算法优化的BP神经网络实现回归预测
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (附源码)springboot工单管理系统 毕业设计 964158
  • (官网安装) 基于CentOS 7安装MangoDB和MangoDB Shell
  • (九)c52学习之旅-定时器
  • (七)MySQL是如何将LRU链表的使用性能优化到极致的?
  • (四)docker:为mysql和java jar运行环境创建同一网络,容器互联
  • (一)Mocha源码阅读: 项目结构及命令行启动
  • (一)基于IDEA的JAVA基础10
  • .NET Core、DNX、DNU、DNVM、MVC6学习资料
  • .net on S60 ---- Net60 1.1发布 支持VS2008以及新的特性
  • .NET 编写一个可以异步等待循环中任何一个部分的 Awaiter
  • .NET 表达式计算:Expression Evaluator
  • .net 反编译_.net反编译的相关问题
  • .NET 实现 NTFS 文件系统的硬链接 mklink /J(Junction)
  • .NET8.0 AOT 经验分享 FreeSql/FreeRedis/FreeScheduler 均已通过测试
  • .net连接oracle数据库
  • ::前边啥也没有
  • @Pointcut 使用