这是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. smarty插件开发代替注册插件方法registerPlugin

  2. 普通请求和ajax请求的区别

    普通请求和ajax请求的区别? 下面的action返回一个json文件,文件内容为sts.*,data1

  3. f2fs解析(一)f2fs如何解决wandering tree

    wandering tree问题是log-structured 文件系统(LFS) 特有的一个问题,因为LFS的脏数据是追加更新的,所以如果一个数据块变脏了,那么那个数据块的直接索引块.间接索引块都会 ...

  4. 10SpringMvc_springmvc快速入门小案例(注解版本)

    第一步:新建案例工程:

  5. WPF使用cefsharp

    最近在公司项目上会用到cefsharp.wpf,不知道为什么按照网上的配置一直无法运行成功,怎么配置可以参考以下这篇博文: http://www.cnblogs.com/TianFang/p/4573 ...

  6. 双绞线线序+POE供电网线

    0 重点 一般情况下会用1236(橙白.橙.绿白.绿)传输数据,1.2用于发送,3.6用于接收,45(蓝.蓝白)电源正极 78(棕白.棕)电源负极. 一 网线线序 12发 36收 二 poe网线供电 ...

  7. unity触发器和碰撞器

    Unity中检测碰撞的方法有两种,一种是触发器一种是碰撞器,现在我来解释一下两种的区别. 触发器:有三种方法,分别是OnTriggerEnter,OnTriggerStay,OnTriggerExit ...

  8. 微信开放平台,微信登陆第三方网站 提示redirect_uri 参数错误

    在微信开放平台上我填写的回调域是:bbs.qiaoshisui.com/LoginApi/WeiXinCallBack,我构造的链接是:https://open.weixin.qq.com/conne ...

  9. Quartz.net打造信息抽取器

    由于最近的一个项目需要定时抽取特定XML信息,然后保存到数据库,最后通过WebApi把手机端要使用的方法给暴露出来,所以去研究了一下Quartz.net.由于项目很小,我没用到Autofac,Repo ...

  10. JS 之DOM对象(1)

    介绍DOM1中底层的一些属性和方法. 节点操作 appendChild() parentNode.appendChild(newNode)  在parentNode节点的最后插入newNode ins ...