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;
}

浙公网安备 33010602011771号