GalaxyOJ-786 (AC自动机)

来源:互联网 发布:os x软件推荐 编辑:程序博客网 时间:2024/06/10 20:04

题目

Problem Description

这是一道很容易ac的简单的字符串题。
给你n个字符串,这个字符串是由小写字母组成。
有q个询问,每次给出x和y。
找到第x个字符串和第y个字符串的连续公共子串同时也是某个字符串的前缀的串(某个字符串是指第一个字符串到第n个字符串的任意一个,包含第x个和第y个)。问这样的串的最长长度是多少。

Input

第一行一个数字n,表示字符串的个数
接下来的n行给出了这n个字符串。
接下来是一个整数q,表示询问个数
接下来的q行,一行有两个整数表示x和y

20%的数据,n,字母总个数<=10
50%的数据,n,字母总个数<=100
100%的数据,n,字母总个数<=100000,q<=100

Output

共q行,一行一个整数,表示第q个询问的答案

Sample Input

3
aaa
baaa
caaa
2
2 3
1 2

Sample Output

3
3

分析

  • 题目就是给 n 个字符串,每次询问给你其中两个两个,问他们两个中是这 n 个串中某个的前缀的的公共连续子串最长可以是多少。
  • 看看题目写着“容易ac的题”,结果是道 AC自动机 的题 罒w罒。
  • 首先把这 n 个串建成一个字典树,然后像 AC自动机 那样弄好 fail 指针,然后对于每个询问的两个串,从每个串第一个字符开始都这样操作一遍——
    • 一直跳fail,直到它到了根节点
    • 把路径上的点打上标记
  • 这样下来,每个打上标记的点所代表的字符串肯定是 n 个串中某个的前缀,且是当前串的一个连续子串。
  • 然后把两个串打的标记记下来,比较一下那些两个串都打过标记的点,他们代表着符合要求(但不一定是最长)的串,然后拿出长度最长(即在字典树中深度最深)的那个长度即可。

程序

#include <cstdio>#include <string>#include <iostream>#include <algorithm>#define X (ch[i][j]-'a')#define son(x) (to[fa][x])using namespace std;string ch[100001];int n,i,j,k,g,xx,yy,ans,L,Q,fa,f[2][105][100005];int head[100005],to[100005][30],cnt;int l,r,dep[100005],q[100005],fail[100005];void get_fail(){    for (i=q[l=r=0]=0; l<=r; i=q[++l])        for (j=0; j<26; j++) if (to[i][j]){            q[++r]=to[i][j];            for (fa=fail[i]; fa && !son(j); fa=fail[fa]);            if (i>0 && son(j)) fail[to[i][j]]=son(j);        }        else to[i][j]=to[fail[i]][j];}void que(string x,int m){    for (k=to[0][x[j=0]-'a'],L=x.length(); j<L; k=to[k][x[++j]-'a']){        for (g=k; g; g=fail[g]){            if (f[m^1][Q][g]){ans=max(dep[g],ans); break;}            if (f[m][Q][g]) break;            f[m][Q][g]=1;        }    }}int main(){    scanf("%d",&n);    for (i=1; i<=n; i++){        cin >>ch[i];        for (j=0,k=0,L=ch[i].length(); j<L; dep[k]=++j)            k=(to[k][X] ? to[k][X] : (to[k][X]=++cnt));    }    get_fail();    for (scanf("%d",&Q); Q--; ans=0){        scanf("%d%d",&xx,&yy);        que(ch[xx],0);        que(ch[yy],1);        printf("%d\n",ans);    }}

提示

  • 我开始用的是字符数组(平常我也是用字符数组的),可是交上去发现居然 RE ,原来是题目说 n,总字符数 都可以为 100000,然后极限数据就是全是一个字符的串,后来无奈用了 string ,然后就过了。
原创粉丝点击