这是AC自动机系列的第一篇

传送门

           Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)0

大意

给出N个仅由小写字母组成的字符串S[1]...S[N],它们的总长度为L。有Q组询问,询问分两类:

1.S[x]是否是S[y]的子序列;

2.S[x]是否是S[y]的子串。

数据范围:

N,L,Q<=100000,有60%的数据满足 L<=100, Q<=1000


Solution

先贴代码,留坑待填。
开始填坑。
首先由于这题的数据范围比较坑,不大可能开二维数组来存字符串,故采用了将各字符串连续存起来的办法,另开一个数组记录各串首字母位置。
void input(int n){
for(int i=; i<n; i++){
scanf("%s", s+beg[i]);
beg[i+]=beg[i]+strlen(s+beg[i]);
}
}
判断子序列询问比较简单,可以O(N)解决。
nt[i][j]表示位置第j个字母在位置i之后(包括位置i)首次出现的位置。从后往前扫一遍就可以打出这个表了。
int nt[N][];
void calc_nt(int n){
memset(nt, -, *beg[n]<<);
for(int i=, j; i<n; i++){
j=beg[i+]-;
nt[j][s[j]-'a']=j;
for(j--; j>=beg[i]; j--)
for(int k=; k<; k++)
if(k==s[j]-'a') nt[j][k]=j;
else nt[j][k]=nt[j+][k];
}
}

查询时只要在串S[j]对应的nt表中不断往后匹配就可以了:

int subseq(int x, int y){
if(len(x)>len(y)) return ;
for(int i=beg[x], j=beg[y]; i<beg[x+]; i++){
if(j>=beg[y+]) return ;
if(nt[j][s[i]-'a']==-) return ;
j=nt[j][s[i]-'a']+;
}
return ;
}

判断子串的询问可用AC自动机离线处理。

AC代码

#include <bits/stdc++.h>
using namespace std; const int N(1e5+);
int beg[N], id[N];
char s[N]; void input(int n){
for(int i=; i<n; i++){
scanf("%s", s+beg[i]);
beg[i+]=beg[i]+strlen(s+beg[i]);
}
} int x[N], y[N];
void preprocess(int q, map<pair<int,int>,int> &mp){
mp.clear();
for(int i=; i<q; i++){
scanf("%d%d", x+i, y+i), x[i]--, y[i]--;
mp[{id[x[i]], id[y[i]]}];
}
} int nt[N][];
void calc_nt(int n){
memset(nt, -, *beg[n]<<);
for(int i=, j; i<n; i++){
j=beg[i+]-;
nt[j][s[j]-'a']=j;
for(j--; j>=beg[i]; j--)
for(int k=; k<; k++)
if(k==s[j]-'a') nt[j][k]=j;
else nt[j][k]=nt[j+][k];
}
} int len(int x){return beg[x+]-beg[x];} int subseq(int x, int y){
if(len(x)>len(y)) return ;
for(int i=beg[x], j=beg[y]; i<beg[x+]; i++){
if(j>=beg[y+]) return ;
if(nt[j][s[i]-'a']==-) return ;
j=nt[j][s[i]-'a']+;
}
return ;
} void solve1(int q, map<pair<int,int>,int> &mp, int *ans){
mp.clear();
for(int i=; i<q; i++){
if(mp.find({x[i], y[i]})==mp.end())
mp[{x[i], y[i]}]=subseq(x[i], y[i]);
ans[i]=mp[{x[i], y[i]}];
}
} int ch[N][], f[N], last[N], val[N];
void init(int i){
memset(ch[i], , sizeof(ch[i]));
f[i]=last[i]=val[i]=;
} void build_trie(int n){
int tot=; init(tot++);
for(int i=, ID=, u; i<n; i++){
for(int j=(u=,beg[i]); j<beg[i+]; j++){
int &v=ch[u][s[j]-'a'];
if(!v) v=tot++, init(v);
u=v;
}
if(!val[u]) val[u]=++ID;
id[i]=val[u];
}
} int que[N];
int build_ac(){
int head=, tail=;
for(int i=; i<; i++){
if(ch[][i]) que[tail++]=ch[][i];
}
for(int u; head!=tail;){
u=que[head++];
for(int i=; i<; i++){
int &v=ch[u][i];
if(v){
f[v]=ch[f[u]][i];
last[v] = val[f[v]] ? f[v] : last[f[v]];
que[tail++]=v;
}
else v=ch[f[u]][i];
}
}
} void solve2(int n, int q, map<pair<int,int>,int> &mp, int *ans){
for(int i=, x, y; i<n; i++){
y=id[i];
for(int j=beg[i], k=; j<beg[i+]; j++){
k=ch[k][s[j]-'a'];
x=val[k];
if(x&& mp.find({x, y})!=mp.end())
mp[{x,y}]=;
for(int l=last[k]; l; l=last[l]){
x=val[l];
if(mp.find({x, y})!=mp.end())
mp[{x,y}]=;
}
}
}
for(int i=; i<q; i++)
ans[i]=mp[{id[x[i]],id[y[i]]}];
}
int ans[][N];
map<pair<int,int>,int> mp[];
int main(){
int T; scanf("%d", &T);
for(int n, q; T--; puts("")){
scanf("%d%d", &n, &q);
input(n);
calc_nt(n);
build_trie(n);
build_ac();
preprocess(q, mp[]);
solve1(q, mp[], ans[]);
solve2(n, q, mp[], ans[]);
for(int i=; i<q; i++) printf("%d%d", ans[][i], ans[][i]);
}
}

HDU #5507 GT and Strings的更多相关文章

  1. HDU 5229 ZCC loves strings 博弈

    题目链接: hdu:http://acm.hdu.edu.cn/showproblem.php?pid=5229 bc:http://bestcoder.hdu.edu.cn/contests/con ...

  2. 矩阵十题【五】 VOJ1049 HDU 2371 Decode the Strings

    题目链接:https://vijos.org/p/1049 题目大意:顺次给出m个置换,重复使用这m个置换对初始序列进行操作.问k次置换后的序列.m<=10, k<2^31. 首先将这m个 ...

  3. hdu 1501 Zipper dfs

    题目链接: HDU - 1501 Given three strings, you are to determine whether the third string can be formed by ...

  4. hdu 6208 The Dominator of Strings【AC自动机】

    hdu 6208 The Dominator of Strings[AC自动机] 求一个串包含其他所有串,找出最长串去匹配即可,但是匹配时要对走过的结点标记,不然T死QAQ,,扎心了.. #inclu ...

  5. HDU 6208 The Dominator of Strings(AC自动机)

    The Dominator of Strings Time Limit: 3000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java ...

  6. HDU 6170 - Two strings | 2017 ZJUT Multi-University Training 9

    /* HDU 6170 - Two strings [ DP ] | 2017 ZJUT Multi-University Training 9 题意: 定义*可以匹配任意长度,.可以匹配任意字符,问 ...

  7. 2017多校第9场 HDU 6170 Two strings DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6170 题意:给了2个字符串,其中第2个字符串包含.和*两种特别字符,问第二个字符串能否和第一个匹配. ...

  8. HDU 6170----Two strings(DP)

    题目链接 Problem Description Giving two strings and you should judge if they are matched.The first strin ...

  9. hdu 6170 Two strings dp

    Two strings Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Prob ...

随机推荐

  1. js原生选项卡(自动播放无缝滚动轮播图)二

    今天分享一下自动播放轮播图,自动播放轮播图是在昨天分享的轮播图的基础上添加了定时器,用定时器控制图片的自动切换,函数中首先封装一个方向的自动播放工能的小函数,这个函数中添加定时器,定时器中可以放向右走 ...

  2. Java常用类库——Runtime

    runtime运行时候,是封装了一个JVM进程的类,每一个JAVA程序实际上启动了一个JVM进程,那么每个JVM对应一个runtime实例.此实例是由JVM为其实例化. 本类的定义中没有构造方法,因为 ...

  3. Xcode6与Xcode5中沙盒的变动以及偏好设置目录的变动

    1.Xcode6模拟器路径与Xcode5模拟器路径对比: (1)Xcode5中模拟器路径为:/Users/用户名/Library/Application Support/iPhone Simulato ...

  4. Linux内核启动

    Linux内核启动过程概述 Linux的启动代码真的挺大,从汇编到C,从Makefile到LDS文件,需要理解的东西很多.毕竟Linux内核是由很多人,花费了巨大的时间和精力写出来的.而且直到现在,这 ...

  5. C# 利用QRCode生成二维码图片

    网上生成二维码的组件是真多,可是真正好用的,并且生成速度很快的没几个,QRCode就是我在众多中找到的,它的生成速度快.但是网上关于它的使用说明,真的太少了,大都是千篇一律的复制粘贴.这是本要用它做了 ...

  6. iBatis.Net(C#)数据库查询

    引用请注明http://www.cnblogs.com/13590/archive/2013/03/14/2958735.html  摘要:查询是数据库SQL语言的核心,本文介绍了通过iBatis.N ...

  7. 亚博 Arduino智能小车实验报告

    亚博 Arduino智能小车实践报告 一.     程序安装准备 首先安装了Arduino板载USB转串口CH340驱动安装包, 若上述程序安装成功,则可以在我的电脑中找到相应的端口 本机端口号为CO ...

  8. WPF开发时光之痕日记本(二)—— MVVM基类

    当我们用MVVM的时候要实现INotifyPropertyChanged,每次都要实现这个接口比较麻烦,所以基类的作用就体现出来了.代码如下: public class ViewModelBase : ...

  9. Bootstrap系列 -- 34. 按钮下拉菜单

    按钮下拉菜单仅从外观上看和上一节介绍的下拉菜单效果基本上是一样的.不同的是在普通的下拉菜单的基础上封装了按钮(.btn)样式效果.简单点说就是点击一个按钮,会显示隐藏的下拉菜单.按钮下拉菜单其实就是普 ...

  10. redis学习笔记——(4)

    一.概述: 在该系列的前几篇博客中,主要讲述的是与Redis数据类型相关的命令,如String.List.Set.Hashes和Sorted-Set.这些命令都具有一个共同点,即所有的操作都是针对与K ...