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. $微信小程序开发实践点滴——Bmob基本REST API的python封装

    Refer:Bmob后端云REST API接口文档:http://docs.bmob.cn/data/Restful/a_faststart/doc/index.html 本文使用python对Bmo ...

  2. 运行报警告UserWarning: Unknown extension is not supported and will be removed warn(msg)

    运行python代码,出现如下警告: C:\Users\niko\PycharmProjects\python_new\venv\lib\site-packages\openpyxl\reader\w ...

  3. 20145201 《Java程序设计》第六周学习总结

    20145201 <Java程序设计>第六周学习总结 教材学习内容总结 本周学习了课本第十.十一章内容,即输入/输出.线程与并行API. 第十章 输入输出 10.1 InputStream ...

  4. React 学习参考资料链接

    node.js官网https://nodejs.org/en/download/ React 入门实例教程http://www.ruanyifeng.com/blog/2015/03/react.ht ...

  5. Spring Boot JDBC 连接数据库

    文本将对在Spring Boot构建的Web应用中,基于MYSQL数据库的几种数据库连接方式进行介绍. 包括JDBC.JPA.MyBatis.多数据源和事务. JDBC 连接数据库 1.属性配置文件( ...

  6. Python 函数定义和使用

    # 函数的概念 # 概念 # 写了一段代码实现了某个小功能; 然后把这些代码集中到一块, 起一个名字; 下一次就可以根据这个名字再次使用这个代码块, 这就是函数 # 作用 # 方便代码的重用 # 分解 ...

  7. cmd下进入oracle sqlplus

    1.sqlplus /nolog 2.connect sys/orcl@ORCL as sysdba 3.select sysdate from dual exit;

  8. Github删除账号方法

    1.登录后点击头像,选择Settings 2.选择Account,然后再选择Delete your account 3.第一个输入框输入邮箱或者用户名,第二个输入框输入delete my accoun ...

  9. js实现继承的方式

    [原文] 前言 JS作为面向对象的弱类型语言,继承也是其非常强大的特性之一.那么如何在JS中实现继承呢?让我们拭目以待. JS继承的实现方式 既然要实现继承,那么首先我们得有一个父类,代码如下: // ...

  10. linux下gzip压缩同样内容大小不一样

    一份数据,两种传输方式进行收集. 一份数据:有多台数据采集节点或者多个数据源 两种方式:一种是从依次多个采集节点或者多个数据源将数据拷贝过来,合并为一个文件 另外一种是多个采集节点或者数据源同时向汇总 ...