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

 

posted @ 2017-08-20 11:31  zxycoder  阅读(162)  评论(0编辑  收藏  举报