hdu6138 多校2017 ac自动机or后缀数组
来源:互联网 发布:网络综艺为什么这么火 编辑:程序博客网 时间:2024/06/16 08:13
题目链接
题目大意:给定n个字符串,m个询问,对于每一个询问,给出x,y 问第x个串和第y个串的相同连续子串当中,作为其他(包括自己)串的前缀的最长长度。
两种思路:第一种ac自动机
首先把所有的串建立一个fail树,那么对于询问把第一个串在树上跑一遍,把所有匹配的节点标记,然后让第二串跑一遍,如果遇到相同匹配的节点,记录当前的最大深度就可以了。
代码:
#include<iostream>#include<cstdio>#include<cmath>#include<algorithm>#include<string>#include<set>#include<map>#include<queue>#include<stack>#include<cstring>#define clr(x) memset(x,0,sizeof(x))using namespace std;#define LL long longconst int N = 100005;struct Trie{ int _next[30]; int fail; int isStr; int dep; int id;}trie[N];int cnt;void Insert(char* s,int len){ int now = 0; int dep = 0; for(int i = 0;i<len;i++) { if(trie[now]._next[s[i]-'a']>0) { now = trie[now]._next[s[i]-'a']; } else { trie[now]._next[s[i]-'a'] = cnt; now = cnt++; } trie[now].dep = ++dep; } trie[now].isStr++; // 字符串少一}void GetFail(){ queue<int>que; que.push(0); trie[0].fail = -1; while(!que.empty()) { int now = que.front(); que.pop(); for(int i =0;i<26;i++) { if(trie[now]._next[i]>0) { int son = trie[now]._next[i]; int pa = trie[now].fail; while(pa>=0 && trie[pa]._next[i]<=0)pa = trie[pa].fail; trie[son].fail = pa>=0?trie[pa]._next[i]:0; que.push(son); } } }}int acmachine(char *obj,int len,int bid,int fid){ int now = 0; int maxlen = 0; for(int i = 0;i<len;i++) { int p = now; while(p>=0 && trie[p]._next[obj[i]-'a']<=0) p = trie[p].fail; now = p>=0?trie[p]._next[obj[i]-'a']:0; int temp = now; while(temp>0) { if(trie[temp].id == fid && trie[temp].dep>maxlen) maxlen = trie[temp].dep; trie[temp].id = bid; temp = trie[temp].fail; } } return maxlen;}int pos[N];int slen[N];int main(){ int t; scanf("%d",&t); while(t--) { cnt = 1; int n; memset(trie,-1,sizeof(trie)); scanf("%d",&n); int id = 0; char str[100005]; for(int i = 0;i<n;i++) { scanf("%s",&str[id]); pos[i] = id; slen[i] = strlen(&str[id]); id += slen[i]+1; Insert(&str[pos[i]],slen[i]); } GetFail(); int m; scanf("%d",&m); int ans = 0; for(int i = 0;i<m;i++) { int x,y; scanf("%d%d",&x,&y); x--; y--; ans = 0; //cout << &str[pos[x]] << " " << &str[pos[y]] << endl; acmachine(&str[pos[x]],slen[x],i+1,0); //cout << trie[3].id << endl; ans = max(ans,acmachine(&str[pos[y]],slen[y],-1,i+1)); printf("%d\n",ans); } } return 0;}
第二种思路:用后缀数组
首先对n个串建立字典树,然后对于每一个询问,把两个串连接在一起,跑一遍后缀数组,然后枚举height数组,如果height[i]中字典序相邻的两个后缀,一个后缀在第一个串当中(即
代码:
#include<iostream>#include<cstdio>#include<cmath>#include<algorithm>#include<string>#include<set>#include<map>#include<queue>#include<stack>#include<cstring>#define clr(x) memset(x,0,sizeof(x))using namespace std;#define LL long longconst int N = 500005;int sa[N],s[N],wa[N], wb[N], _ws[N], wv[N];int _rank[N], height[N];bool cmp(int r[], int a, int b, int l){ return r[a] == r[b] && r[a+l] == r[b+l];}void da(int r[], int sa[], int n, int m){ int i, j, p, *x = wa, *y = wb; for (i = 0; i < m; ++i) _ws[i] = 0; for (i = 0; i < n; ++i) _ws[x[i]=r[i]]++; for (i = 1; i < m; ++i) _ws[i] += _ws[i-1]; for (i = n-1; i >= 0; --i) sa[--_ws[x[i]]] = i; for (j = 1, p = 1; p < n; j *= 2, m = p) { for (p = 0, i = n - j; i < n; ++i) y[p++] = i; for (i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j; for (i = 0; i < n; ++i) wv[i] = x[y[i]]; for (i = 0; i < m; ++i) _ws[i] = 0; for (i = 0; i < n; ++i) _ws[wv[i]]++; for (i = 1; i < m; ++i) _ws[i] += _ws[i-1]; for (i = n-1; i >= 0; --i) sa[--_ws[wv[i]]] = y[i]; for (std::swap(x, y), p = 1, x[sa[0]] = 0, i = 1; i < n; ++i) x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++; }}void calheight(int r[], int sa[], int n){ int i, j, k = 0; for (i = 1; i <= n; ++i) _rank[sa[i]] = i; for (i = 0; i < n; height[_rank[i++]] = k) for (k?k--:0, j = sa[_rank[i]-1]; r[i+k] == r[j+k]; k++);}struct node{ char ch; node* chil[30]; node() { _clear(); } void _clear() { clr(chil); ch = 0; }}tree;void InsertTree(char le[],int len){ node* p = &tree; for(int i = 0;i<len;i++) { if(p->chil[le[i]-'a']==NULL) { node* temp = new node(); temp->ch = le[i]; p->chil[le[i]-'a'] = temp; } p = p->chil[le[i]-'a']; }}int Query(char le[],int len){ int cnt = 0; node* p = &tree; for(int i = 0;i<len;i++) { if(p->chil[le[i]-'a']!=NULL) { cnt++; p = p->chil[le[i]-'a']; } else break; } return cnt;}char str[N];int pos[N];int main(){ int t; scanf("%d",&t); while(t--) { tree._clear(); int n; scanf("%d",&n); int cnt = 0; for(int i = 0;i<n;i++) { scanf("%s",str+cnt); pos[i] = cnt; int len = strlen(str+cnt); InsertTree(str+cnt,len); cnt += len+1; } int m; scanf("%d",&m); while(m--) { int x,y; scanf("%d%d",&x,&y); char* chx = str+pos[x-1]; char* chy = str+pos[y-1]; int lenx = strlen(chx); int leny = strlen(chy); int s[100005]; for(int i = 0;i<lenx;i++) { s[i] = chx[i]; } s[lenx] = 1; for(int i = 0;i<leny;i++) { s[lenx+1+i] = chy[i]; } s[lenx+leny+1] = 0;//cout << lenx << " " << leny << endl; da(s,sa,lenx+leny+2,128); calheight(s,sa,lenx+leny+1); int mx = 0; for(int i = 1;i<lenx+leny+1;i++) { if(height[i]<=mx)continue; if(sa[i-1]<lenx&sa[i]>lenx) { mx = max(mx,Query(str+pos[x-1]+sa[i-1],height[i])); } else if(sa[i-1]>lenx && sa[i]<lenx) { mx = max(mx,Query(str+pos[x-1]+sa[i],height[i])); } } printf("%d\n",mx); } } return 0;}
阅读全文
0 0
- hdu6138 多校2017 ac自动机or后缀数组
- 字符串 KMP Trie AC自动机 后缀数组
- manacher 后缀数组 AC自动机 回文自动机 知识点讲解 课件
- hdu6138 Fleet of the Eternal Throne AC自动机
- 2017 暑假艾教集训 day10 AC自动机+马拉车+后缀数组 +kmp
- HDU3065 病毒侵袭持续中(AC自动机或后缀数组)
- [AC自动机 fail树 || 后缀数组] BZOJ 3172 [Tjoi2013]单词
- 后缀数组/AC自动机——BZOJ3172 [Tjoi2013]单词
- HDU 6208 ac自动机 hash sam 后缀数组
- 字符串模板 KMP AC自动机 Manacher 后缀数组
- [BZOJ2754] 喵星球上的点名 - AC自动机/后缀数组/后缀自动机/玄学♂暴力
- 【后缀自动机】自动机<->后缀树<->后缀数组
- AC自动机数组写法
- 后缀自动机 转变为 后缀数组
- BZOJ 题目3172: [Tjoi2013]单词(AC自动机||AC自动机+fail树||后缀数组暴力||后缀数组+RMQ+二分等五种姿势水过)
- http://acm.buaa.edu.cn/problem/533/ AC 自动机加后缀数组
- [后缀数组+dp/AC自动机+dp+线段树] hdu 4117 GRE Words
- HDU 6138 Fleet of the Eternal Throne AC自动机||后缀数组
- 【51Nod1257】背包问题 V3
- 剑指offer-判断平衡二叉树
- linux下使用润乾V5设计器乱码问题
- eval解析JSON中的注意点 在JS中将JSON的字符串解析成JSON数据格式,一般有两种方式: 1.一种为使用eval()函数。 2. 使用Function对象来进行返回解析。 使用eval
- 计算机修炼之路--------JavaScript法术的学习笔记(三)之JavaScript语法(二)
- hdu6138 多校2017 ac自动机or后缀数组
- Debug Knowledge Base
- poj--1961--Period
- C/C++的传指针和引用
- HDU-4847:Wow! Such Doge!(震惊!!!kmp模板题。。。kmp:我不要面子的啊)
- Jmeter中Websocket协议支持包的使用
- codeforces734D
- tensorflow基础
- 只用路径上传文件,不用手动选择文件上传