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.

InputThe 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 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 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 T≤5

0<N,Q≤100000 0<N,Q≤100000

∑Si+Pi≤500000 ∑Si+Pi≤500000

∑Wi≤500000 ∑Wi≤500000

OutputFor 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次询问,每次询问给出pre和suf,统计有多少个单词的前缀为pre,后缀为suf,而且要满足二者不相交。

思路:我们把询问建立AC自动机,单词用来跑AC自动机,跑到了就累计。

合理建立AC自动机的方式为:每个询问转为为 suf+'{'+pre;

跑AC自动机的方式为: 每个单词转化为 S+’{‘+S;

跑的时候如果fail可以走到某个询问,说明这个询问是这里的前后缀。(AC了但是不严谨的代码)

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
char c[maxn],s[maxn],pre[maxn],suf[maxn];
int tot,F[maxn],L[maxn],ch[maxn][],cnt,pos[maxn];
int N,Q,dep[maxn],sum[maxn],fail[maxn],q[maxn],head,tail;
void insert(int opt){
int Now=,len1=strlen(suf+),len2=strlen(pre+);
rep(i,,len1){
if(!ch[Now][suf[i]-'a']) ch[Now][suf[i]-'a']=++cnt,sum[cnt]=;
Now=ch[Now][suf[i]-'a'];
}
if(!ch[Now][]) ch[Now][]=++cnt,sum[cnt]=; Now=ch[Now][];
rep(i,,len2){
if(!ch[Now][pre[i]-'a']) ch[Now][pre[i]-'a']=++cnt,sum[cnt]=;
Now=ch[Now][pre[i]-'a'];
}
pos[opt]=Now; dep[Now]=len1+len2;
}
void buildfail()
{
head=tail=;
for(int i=;i<=;i++) if(ch[][i]) q[++head]=ch[][i];
while(tail<head){
int Now=q[++tail];
for(int i=;i<=;i++){
if(ch[Now][i]) {
fail[ch[Now][i]]=ch[fail[Now]][i];
q[++head]=ch[Now][i];
}
else ch[Now][i]=ch[fail[Now]][i];
}
}
}
void solve(int B,int len)
{
int Now=;
rep(i,B+,B+len) Now=ch[Now][c[i]-'a'];
Now=ch[Now][];
rep(i,B+,B+len){
Now=ch[Now][c[i]-'a']; int tmp=Now;
while(dep[tmp]>len) tmp=fail[tmp]; sum[tmp]++;
}
}
int main()
{
int T; scanf("%d",&T);
while(T--){
tot=cnt=;
memset(fail,,sizeof(fail));
memset(ch,,sizeof(ch));
scanf("%d%d",&N,&Q);
rep(i,,N){
scanf("%s",s+);
L[i]=strlen(s+); F[i]=tot;
rep(j,,L[i]) c[++tot]=s[j]; //保存单词
}
rep(i,,Q){
scanf("%s%s",pre+,suf+);
insert(i);
}
buildfail();
rep(i,,N) solve(F[i],L[i]);
for(int i=cnt;i>=;i--) sum[fail[q[i]]]+=sum[q[i]]; //累加前缀和
rep(i,,Q) printf("%d\n",sum[pos[i]]);
}
return ;
}

虽然上面的代码AC了,但是我感觉是可以hack掉,应该是数据比较水。 因为一个单词对一个询问最多有一个贡献,而这样跑下来有的单词的贡献可能大于1,所以我们加一个时间戳,保证每个单词的贡献最多为1。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
char c[maxn],s[maxn],pre[maxn],suf[maxn];
int tot,F[maxn],L[maxn],ch[maxn][],cnt,pos[maxn],Laxt[maxn];
int N,Q,dep[maxn],sum[maxn],fail[maxn],q[maxn],head,tail;
void insert(int opt){
int Now=,len1=strlen(suf+),len2=strlen(pre+);
rep(i,,len1){
if(!ch[Now][suf[i]-'a']) ch[Now][suf[i]-'a']=++cnt,sum[cnt]=;
Now=ch[Now][suf[i]-'a'];
}
if(!ch[Now][]) ch[Now][]=++cnt,sum[cnt]=; Now=ch[Now][];
rep(i,,len2){
if(!ch[Now][pre[i]-'a']) ch[Now][pre[i]-'a']=++cnt,sum[cnt]=;
Now=ch[Now][pre[i]-'a'];
}
pos[opt]=Now; dep[Now]=len1+len2;
}
void buildfail()
{
head=tail=;
for(int i=;i<=;i++) if(ch[][i]) q[++head]=ch[][i];
while(tail<head){
int Now=q[++tail];
for(int i=;i<=;i++){
if(ch[Now][i]) {
fail[ch[Now][i]]=ch[fail[Now]][i];
q[++head]=ch[Now][i];
}
else ch[Now][i]=ch[fail[Now]][i];
}
}
}
void solve(int time,int B,int len)
{
int Now=;
rep(i,B+,B+len) Now=ch[Now][c[i]-'a'];
Now=ch[Now][];
rep(i,B+,B+len){
Now=ch[Now][c[i]-'a']; int tmp=Now;
while(tmp) {
if(Laxt[tmp]==time) break;
Laxt[tmp]=time;//加一个时间戳,保证每个单词的贡献最多为1
if(dep[tmp]<=len) sum[tmp]++;
tmp=fail[tmp];
}
}
}
int main()
{
int T; scanf("%d",&T);
while(T--){
tot=cnt=;
memset(fail,,sizeof(fail));
memset(ch,,sizeof(ch));
memset(Laxt,,sizeof(Laxt));
scanf("%d%d",&N,&Q);
rep(i,,N){
scanf("%s",s+);
L[i]=strlen(s+); F[i]=tot;
rep(j,,L[i]) c[++tot]=s[j]; //保存单词
}
rep(i,,Q){
scanf("%s%s",pre+,suf+);
insert(i);
}
buildfail();
rep(i,,N) solve(i,F[i],L[i]);
rep(i,,Q) printf("%d\n",sum[pos[i]]);
}
return ;
}

HDU - 6096 :String (AC自动机,已知前后缀,匹配单词,弱数据)的更多相关文章

  1. 2017多校第6场 HDU 6096 String AC自动机

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6096 题意:给了一些模式串,然后再给出一些文本串的不想交的前后缀,问文本串在模式串的出现次数. 解法: ...

  2. HDU 6096 String (AC自动机)

    题意:给出n个字符串和q个询问,每次询问给出两个串 p 和 s .要求统计所有字符串中前缀为 p 且后缀为 s (不可重叠)的字符串的数量. 析:真是觉得没有思路啊,看了官方题解,真是好复杂. 假设原 ...

  3. HDU 6096 String(AC自动机+树状数组)

    题意 给定 \(n\) 个单词,\(q\) 个询问,每个询问包含两个串 \(s_1,s_2\),询问有多少个单词以 \(s_1\) 为前缀, \(s_2\) 为后缀,前后缀不能重叠. \(1 \leq ...

  4. ZOJ 3228 Searching the String(AC自动机)

    Searching the String Time Limit: 7 Seconds      Memory Limit: 129872 KB Little jay really hates to d ...

  5. 【XSY3320】string AC自动机 哈希 点分治

    题目大意 给一棵树,每条边上有一个字符,求有多少对 \((x,y)(x<y)\),满足 \(x\) 到 \(y\) 路径上的边上的字符按顺序组成的字符串为回文串. \(1\leq n\leq 5 ...

  6. ZOJ3228 Searching the String —— AC自动机 + 可重叠/不可重叠

    题目链接:https://vjudge.net/problem/ZOJ-3228 Searching the String Time Limit: 7 Seconds      Memory Limi ...

  7. 如何利用AI识别未知——加入未知类(不太靠谱),检测待识别数据和已知样本数据的匹配程度(例如使用CNN降维,再用knn类似距离来实现),将问题转化为特征搜索问题而非决策问题,使用HTM算法(记忆+模式匹配预测就是智能),GAN异常检测,RBF

    https://www.researchgate.net/post/How_to_determine_unknown_class_using_neural_network 里面有讨论,说是用rbf神经 ...

  8. HDU 6096 String (AC自动机)

    题目链接 Problem Description Bob has a dictionary with N words in it. Now there is a list of words in wh ...

  9. hdu 6086 -- Rikka with String(AC自动机 + 状压DP)

    题目链接 Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, s ...

随机推荐

  1. linux命令(6/11)--修改文件的用户组chgrp和文件所有者chown

    在lunix系统里,文件或目录的权限的掌控以拥有者及所诉群组来管理.可以使用chgrp指令取变更文件与目录所属群组,这种方式采用群组名称或群组识别码都可以.Chgrp命令就是change group的 ...

  2. C# Winform DataGrid 绑定List<> Or ObservableCollection<> 类型无法自动刷新问题

    当DataGrid通过绑定List<> Or ObservableCollection<> 类型数据,通过INofityPropertyChanged接口通知数据改变进行刷新无 ...

  3. 将从数据库中获取的数据写入到Excel表中

    pom.xml文件写入代码,maven自动加载poi-3.1-beta2.jar <!-- https://mvnrepository.com/artifact/poi/poi --> & ...

  4. Vmware ESXi 6.0 多Vlan部署,vSphere Client管理方法

    背景: 公司IT部门新购了两台服务器与一台存储,打算做虚拟化,并将存储分成两个部分,分别配给那两台服务器.在宿主机上要安装的虚拟机属于不同的网段,这就涉及了多VLAN,当然这并不是多么高深的技术,属于 ...

  5. MySQL数据库的主从同步复制配置

    一.主从同步机制原理 MYSQL主从同步是在MySQL主从复制(Master-Slave Replication)基础上实现的,通过设置在Master MySQL上的binlog(使其处于打开状态), ...

  6. wyx20162314实验报告1

    北京电子科技学院BESTI实验报告 课程:程序设计与数据结构 班级: 1623 姓名: 王译潇 学号:20162310 指导教师:娄佳鹏老师.王志强老师 实验日期:2017年3月26号 实验密级: 非 ...

  7. Book Review of “The practice of programming” (Ⅱ)

    The practice of programming Chapter 2 Algorithms and Data Structures Searching sequential search (li ...

  8. WIN7下PHP无法开启CURL,终极解决方案

    常规做法: 1)extension=php_curl.dll之外 2)把libeay32.dll.ssleay32.dll.php_curl.dll复制到C:\Windows\SysWOW64目录下 ...

  9. 深入理解JVM4——线程安全

    浅谈java内存模型 不同的平台,内存模型是不一样的,但是jvm的内存模型规范是统一的.其实java的多线程并发问题最终都会反映在java的内存模型上,所谓线程安全无非是要控制多个线程对某个资源的有序 ...

  10. Java 四大作用域总结

    一.ServletContext 1.生命周期:当Web应用被加载进容器时创建代表整个web应用的ServletContext对象,当服务器关闭或Web应用被移除时,ServletContext对象跟 ...