2017多校第8场 HDU 6138 Fleet of the Eternal Throne AC自动机或者KMP

Posted Lsxxxxxxxxxxxxx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}

 

以上是关于2017多校第8场 HDU 6138 Fleet of the Eternal Throne AC自动机或者KMP的主要内容,如果未能解决你的问题,请参考以下文章

2017多校第8场 HDU 6134 Battlestation Operational 莫比乌斯反演

2017多校第8场 HDU 6143 Killer Names 容斥,组合计数

hdu6406 Taotao Picks Apples 多校第8场1010

2017多校第6场 HDU 6105 Gameia 博弈

2017多校第10场 HDU 6172 Array Challenge 猜公式,矩阵幂

2017多校第10场 HDU 6181 Two Paths 次短路