HDU - 6096 :String (AC自动机,已知前后缀,匹配单词,弱数据)
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自动机,已知前后缀,匹配单词,弱数据)的更多相关文章
- 2017多校第6场 HDU 6096 String AC自动机
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6096 题意:给了一些模式串,然后再给出一些文本串的不想交的前后缀,问文本串在模式串的出现次数. 解法: ...
- HDU 6096 String (AC自动机)
题意:给出n个字符串和q个询问,每次询问给出两个串 p 和 s .要求统计所有字符串中前缀为 p 且后缀为 s (不可重叠)的字符串的数量. 析:真是觉得没有思路啊,看了官方题解,真是好复杂. 假设原 ...
- HDU 6096 String(AC自动机+树状数组)
题意 给定 \(n\) 个单词,\(q\) 个询问,每个询问包含两个串 \(s_1,s_2\),询问有多少个单词以 \(s_1\) 为前缀, \(s_2\) 为后缀,前后缀不能重叠. \(1 \leq ...
- ZOJ 3228 Searching the String(AC自动机)
Searching the String Time Limit: 7 Seconds Memory Limit: 129872 KB Little jay really hates to d ...
- 【XSY3320】string AC自动机 哈希 点分治
题目大意 给一棵树,每条边上有一个字符,求有多少对 \((x,y)(x<y)\),满足 \(x\) 到 \(y\) 路径上的边上的字符按顺序组成的字符串为回文串. \(1\leq n\leq 5 ...
- ZOJ3228 Searching the String —— AC自动机 + 可重叠/不可重叠
题目链接:https://vjudge.net/problem/ZOJ-3228 Searching the String Time Limit: 7 Seconds Memory Limi ...
- 如何利用AI识别未知——加入未知类(不太靠谱),检测待识别数据和已知样本数据的匹配程度(例如使用CNN降维,再用knn类似距离来实现),将问题转化为特征搜索问题而非决策问题,使用HTM算法(记忆+模式匹配预测就是智能),GAN异常检测,RBF
https://www.researchgate.net/post/How_to_determine_unknown_class_using_neural_network 里面有讨论,说是用rbf神经 ...
- HDU 6096 String (AC自动机)
题目链接 Problem Description Bob has a dictionary with N words in it. Now there is a list of words in wh ...
- hdu 6086 -- Rikka with String(AC自动机 + 状压DP)
题目链接 Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, s ...
随机推荐
- 【Github教程】史上最全github使用方法:github入门到精通(转自eoeandroid.com)
本文来源:http://www.eoeandroid.com/thread-274556-1-1.html 另附经典教程网址 :http://wuyuans.com/2012/05/github-si ...
- function func(){} 与 var func=function(){}的区别
1 var func =function(){} ,即和 var 变量的特性 一样. func 变量名提前,但是不会初始化,直到执行到初始化代码. 2 function func(){} ...
- Linux静默安装Oracle
打算在云服务器上装oracle服务,以前DBA美眉都是在图形化界面下安装,这次抓瞎了.赶紧上网查查,静默安装可以解决问题.于是乎赶紧开始部署,过程如下.安装环境:操作系统:CentOS 7内存:11G ...
- css盒模型不同浏览器下解释不同 解决办法
盒子模型是css中一个重要的概念,理解了盒子模型才能更好的排版.其实盒子模型有两种,分别是 ie 盒子模型和标准 w3c 盒子模型.他们对盒子模型的解释各不相同,先来看看我们熟知的标准盒子模型: 从上 ...
- article标准用法
article代表一个在文档.页面或者网站中自成一体的内容 其目的是为了让开或重用 譬如论坛的帖子.博客的文章.一片用户的评论.一个互动的widget小工具 article 会有一个标题(通常在hea ...
- 20145201《Java程序设计》课程总结
每周读书笔记链接汇总 第一周读书笔记:http://www.cnblogs.com/20145201lzx/p/5249064.html 第二周读书笔记:http://www.cnblogs.com/ ...
- 用树状数组求逆序对数(poj2299)
Ultra-QuickSort Time Limit: 7000MS Memory Limit: 65536K Total Submissions: 46995 Accepted: 17168 ...
- Spring注解(环境)
以数据库为例: 引入 c3p0数据源maven坐标 数据库驱动 @Configuration @PropertySource("classpath:/db.config.properties ...
- eclipse设置控制台字体大小
步骤如下
- java 处理emoji表情信息转换为String
2种方式实现: 注意:如果发现运行时java.lang.NoClassDefFoundError:异常就是缺少了jar包.添加对应的jar包就可以. 一.emoji-java-4.0.0.jar实现 ...