zoukankan      html  css  js  c++  java
  • 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
    ", 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
    ", ans);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    Linux Hung Task分析
    Linux内存都去哪了:(1)分析memblock在启动过程中对内存的影响
    《Linux/UNIX系统编程手册》第63章 IO多路复用、信号驱动IO以及epoll
    Linux内核和用户空间通信之netlink
    Linux soft lockup分析
    一款DMA性能优化记录:异步传输和指定实时信号做async IO
    Linux下时钟框架实践---一款芯片的时钟树配置
    使用Kernel NetEm和tc模拟复杂网络环境
    使用Flame Graph进行系统性能分析
    sigsuspend()阻塞:异步信号SIGIO为什么会被截胡?
  • 原文地址:https://www.cnblogs.com/spfa/p/7399359.html
Copyright © 2011-2022 走看看