• 1212: [HNOI2004]L语言


    题意:给n个单词,m个串,问每个串满足条件的最长前缀,条件:该前缀S能被拆成几个连续的单词(S中的每个字符出现并且唯一出现在某一个单词中)

    题解:有dp的思想,假设当前字符的位置为 j,如果当前字符能被理解,则存在 i ∈ (0, j),Si~Sj 是一个单词。因为单词的长度只有20可以暴力向前找。考虑AC自动机,一个节点的fail指向的是以当前串的最长后缀,所以沿着每个节点的fail指针不断向上跳,判断是否存在一个j就行了(单词长度较短,至多跳20次)。

    struct node {
        int lengh, fail, Count, vis[26];
        node() {
            mem(vis, 0);
            fail = Count = lengh = 0;
        }
    };
    
    struct Acmation {
        int tot, use[2000010];
        node a[300];
    
        void Inite() {
            tot = 0;
        }
        void Insert(char *s) {
            int n =strlen(s);
            int now = 0;
            rep(i, 0, n) {
                int id = s[i] - 'a';
                if (!a[now].vis[id]) a[now].vis[id] = ++tot;
                now = a[now].vis[id];
            }
            a[now].Count++;
            a[now].lengh = n;
        }
        void getFail() {
            queue<int> q;
            rep(i, 0, 26) if (a[0].vis[i]) {
                a[a[0].vis[i]].fail = 0;
                q.push(a[0].vis[i]);
            }
            while(!q.empty()) {
                int now = q.front();
                q.pop();
                rep(i, 0, 26) {
                    if (a[now].vis[i]) {
                        a[a[now].vis[i]].fail = a[a[now].fail].vis[i];
                        q.push(a[now].vis[i]);
                    }
                    else {
                        a[now].vis[i] = a[a[now].fail].vis[i];
                    }
                }
            }
        }
        void Query(char *s) {
            mem(use, 0);
            use[0] = 1;
    
            int n = strlen(s);
            int now = 0;
            rep(i, 0, n) {
                int id = s[i] - 'a';
                now = a[now].vis[id];
                for (int j = now; j; j = a[j].fail) if (a[j].Count) use[i] |= use[i - a[j].lengh];
            }
    
            int ans = 0;
            rep(i, 0, n) if (use[i]) ans = max(ans, i + 1);
            pr(ans);
        }
    };
    
    int n, m;
    
    Acmation ac;
    
    int main()
    {
        ac.Inite();
    
        sc(n), sc(m);
        rep(i, 0, n) {
            char s[20];
            scanf("%s", s);
            ac.Insert(s);
        }
        ac.getFail();
    
        char s[2000010];
        rep(i, 0, m) {
            scanf("%s", s);
            ac.Query(s);
        }
    
        return 0;
    }
  • 相关阅读:
    跨浏览器右键复制实现
    在eclipse里如何快速定位到某一行?
    为数据库中的表添加字段步骤
    一键安装openstack juno 之controller node.
    Linux的/etc/services文件的作用?
    docker and ssh issues
    yum change source repo centos共存安装sun jdk6和jdk7
    random and password 在Linux下生成crypt加密密码的方法,shell 生成指定范围随机数与随机字符串
    OpenStack,ceph
    那些证书相关的玩意儿(SSL,X.509,PEM,DER,CRT,CER,KEY,CSR,P12等)[zz]
  • 原文地址:https://www.cnblogs.com/zgglj-com/p/9720726.html
Copyright © 2020-2023  润新知