博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
2017 多校6 String
阅读量:6980 次
发布时间:2019-06-27

本文共 3589 字,大约阅读时间需要 11 分钟。

(ac自动机)

题意:

给一本有\(n\)个单词的字典

\(q\)个查询 \(pref_i,suff_i\) 查询字典里有多少单词前缀匹配\(pref_i\),后缀同时匹配\(suff_i\),并且

\(pref_i\)\(suf_i\)不相交

\(0 < n ,q <= 1e5\)

$ \sum (|pref_i| + |suff_i|) <= 5e5$
$ \sum |w_i| <= 5e5$
保证每组查询的前后缀不相交

思路:

forever97大神的这个很不错,比起题解的做法来说,更加符合字符串的套路吧

所有查询一起处理,把查询按$suff_i $ * $pref_i $,

中间用隔开的形式拼接起来,丢到ac自动机里
然后对于字典里的每个单词 扩展成两倍,同样中间用
隔开,
在ac自动机里查询有多少个前后缀是该字符串的子串,比较一下长度就可以知道前后缀是否相交

这样就变成了最简单的在一个文本串中找哪些字符串出现过的问题了

#include
#define LL long long#define P pair
#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define ls rt<<1#define rs (rt<<1|1)using namespace std;int read(){ int x = 0; char c = getchar(); while(c < '0' || c > '9') c = getchar(); while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar(); return x;}const int SIZE = 27;const int MAXNODE = 1e6 + 10;const int N = 1e6 + 10;char word[N],wo[N];char pre[N],suf[N];int w_len[N];int pos[N];int ans[N];struct AC{ int ch[MAXNODE][SIZE]; int f[MAXNODE],last[MAXNODE],val[MAXNODE],length[MAXNODE]; int sz; void init(){sz = 1;memset(ch[0],0,sizeof(ch[0]));length[0]=0;} int idx(char c){return c - 'a';} int _insert(char *s,int v){ int u = 0,len = strlen(s); for(int i = 0;i < len;i++){ int c = idx(s[i]); if(!ch[u][c]){ memset(ch[sz],0,sizeof ch[sz]); val[sz] = 0; length[sz] = i + 1; ch[u][c] = sz++; } u = ch[u][c]; } if(!val[u]) {ans[u] = 0,val[u] = v;} return u; } void getFail(){ queue
q; f[0] = 0; for(int c = 0;c < SIZE;c++){ int u = ch[0][c]; if(u){ f[u] = 0; q.push(u); last[u] = 0; } } while(!q.empty()){ int r = q.front();q.pop(); for(int c = 0;c < SIZE;c++){ int u = ch[r][c]; if(!u){ch[r][c] = ch[f[r]][c];continue;} q.push(u); int v = f[r]; while(v && !ch[v][c]) v = f[v]; f[u] = ch[v][c]; last[u] = val[f[u]]?f[u]:last[f[u]]; } } } void cal(int len,int u){ if(u) { if(length[u] <= len) ans[u]++; cal(len,last[u]); } } void Find(char *s,int l){ int len = strlen(s),u = 0; for(int i = 0;i < len;i++){ u = ch[u][idx(s[i])]; if(val[u]) cal(l,u); else if(last[u]) cal(l,last[u]); } }}ac;int main(){ int T,n,q; T = read(); while(T--){ n = read(),q = read(); int total = 0; for(int i = 1;i <= n;i++){ scanf("%s",wo); w_len[i] = strlen(wo); for(int j = 0;j < w_len[i];j++) word[j + total] = wo[j]; total += w_len[i]; } ac.init(); for(int i = 1;i <= q;i++){ scanf("%s%s",pre,suf); int l = strlen(pre),r = strlen(suf); suf[r]='z'+1; for(int j = 0;j < l;j++) suf[r+1+j] = pre[j]; suf[l + r + 1] = '\0'; pos[i] = ac._insert(suf,i); }; ac.getFail(); int now = 0; for(int i = 1;i <= n;i++) { for(int j = 0;j < w_len[i];j++) pre[j + w_len[i] + 1] = pre[j] = word[now + j]; pre[w_len[i]] = 'z' + 1; pre[2 * w_len[i] + 1] = '\0'; ac.Find(pre,w_len[i]+1); now += w_len[i]; } for(int i = 1;i <= q;i++) printf("%d\n",ans[pos[i]]); } return 0;}

转载于:https://www.cnblogs.com/jiachinzhao/p/7353259.html

你可能感兴趣的文章
CSS强制文本在一行内显示若有多余字符则使用省略号表示
查看>>
蛋花花谈Web前端工程师掌握这些技能更加顺利工作
查看>>
AJPFX的反射学习笔记
查看>>
Android学习--08-ListView
查看>>
polymer中的notify和reflectToAttribute
查看>>
Java排序二叉树
查看>>
从其他机构转投乾颐堂的同学pass感言
查看>>
卷积神经网络CNN原理以及TensorFlow实现
查看>>
教程:怎样处理资源管理器崩溃退出的问题
查看>>
JavaScript和jquery分别实现简单的跑马灯效果
查看>>
缓存涉及的http头,虽然很多不懂但是我也粘出来,希望大家帮我一想分析
查看>>
调试 Dockerfile - 每天5分钟玩转 Docker 容器技术(15)
查看>>
我的友情链接
查看>>
Oracle计算时间跨度的函数
查看>>
python进程之间消息监控程序
查看>>
Abset Line Number Information
查看>>
设置grub密码
查看>>
去除文件中<feff>
查看>>
我的学习计划 2015
查看>>
MySQL中 TIMESTAMP类型 和 DATETIME类型 的区别
查看>>