2017多校第8场 HDU 6138 Fleet of the Eternal Throne AC自动机或者KMP
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6138
题意:给n个串,每次询问x号串和y号串的最长公共子串的长度,这个子串必须是n个串中某个串的前缀
解法1:AC自动机。做法是把n个串建成AC自动机,前缀树中每个节点都当做结尾节点,val赋为trie树深度,然后把x串丢进自动机里,把匹配到的前缀节点染个色,再把y串丢进去,遇到同样颜色的前缀节点就更新一下答案。
#include <bits/stdc++.h> using namespace std; const int N = 1e5+10; const int M = 5e5+10; const int S = 26; struct AcAutomata{ int root,sz; int nxt[M][S],fail[M],val[M],col[N]; int newnode(){ val[sz] = col[sz] = 0; memset(nxt[sz], -1, sizeof(nxt[sz])); return sz++; } void init(){ memset(val, 0, sizeof(val)); sz = 0; root = newnode(); } void insert(char *s){ int u=root; int len=strlen(s); for(int i=0; i<len; i++){ int id=s[i]-'a'; if(nxt[u][id]==-1) nxt[u][id]=newnode(); val[nxt[u][id]]=val[u]+1; u=nxt[u][id]; } } void build(){ queue <int> q; fail[root] = root; for(int i=0; i<S; i++){ int &v = nxt[root][i]; if(~v){ fail[v] = root; q.push(v); } else{ v = root; } } while(q.size()){ int u = q.front(); q.pop(); for(int i = 0; i < S; i++){ int &v = nxt[u][i]; if(~v){ fail[v] = nxt[fail[u]][i]; q.push(v); } else{ v = nxt[fail[u]][i]; } } } } void update(char *s, int x){ int len = strlen(s); int u=root; for(int i=0; i<len; i++){ int id=s[i]-'a'; u=nxt[u][id]; int tmp=u; while(tmp){ col[tmp]=x; tmp=fail[tmp]; } } } int query(char *s, int x){ int len = strlen(s); int u = root; int ans = 0; for(int i=0; i<len; i++){ int id=s[i]-'a'; u=nxt[u][id]; int tmp=u; while(tmp){ if(col[tmp]==x) ans=max(ans, val[tmp]); tmp=fail[tmp]; } } return ans; } }ZXY; char s[N]; int pos[N]; int main() { int T,n,q; scanf("%d", &T); while(T--) { scanf("%d", &n); ZXY.init(); int d=1; for(int i=1; i<=n; i++){ pos[i]=d; scanf("%s", s+d); ZXY.insert(s+d); int len=strlen(s+d); d+=len+1; } ZXY.build(); scanf("%d", &q); int id=1; while(q--) { int x, y; scanf("%d%d",&x,&y); ZXY.update(s+pos[x],id); int ans = ZXY.query(s+pos[y],id); ++id; printf("%d\n", ans); } } return 0; }
解法2:KMP,直接枚举n个串做KMP。。
#include<bits/stdc++.h> using namespace std; const int maxn = 1e5 + 5; vector<int> Next[maxn]; string str[maxn]; void getnext(string &s, vector<int> &nxt) { int len = s.size(); nxt.resize(len); nxt[0] = -1; int i, j = -1; for(i = 1; i < len; i++) { while(j >= 0 && s[j + 1] != s[i]) j = nxt[j]; if(s[j + 1] == s[i]) j++; nxt[i] = j; } } int getMax(string &s, int strid) { int len = s.size(); int i, j = -1; int ret = 0; for(i = 0; i < len; i++) { while(j >= 0 && str[strid][j + 1] != s[i]) j = Next[strid][j]; if(str[strid][j + 1] == s[i]) j++; ret = max(ret, j + 1); } return ret; } char buf[maxn]; int main() { int T; scanf("%d", &T); while(T--) { int n; scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%s", buf); str[i] = buf; getnext(str[i], Next[i]); } int q; scanf("%d", &q); while(q--) { int x, y; scanf("%d %d", &x, &y); int ans = 0; for(int i = 1; i <= n; i++) { int u = getMax(str[x], i); int v = getMax(str[y], i); ans = max(ans, min(u, v)); } printf("%d\n", ans); } } return 0; }