• AC自动机谜题


    兔子们在玩字符串的游戏。首先,它们拿出了一个字符串集合 S,然后它们定义一个字符串为“好”的,当且仅当它可以被分成非空的两段,其中每一段都是字符串集合 S 中某个字符串的前缀。
    比如对于字符串集合{"abc", "bca"},字符串"abb","abab"是“好”的("abb" = "ab"+"b", abab = "ab" + "ab"),而字符串“bc”不是“好”的。
    兔子们想知道,一共有多少不同的“好”的字符串。

    输入格式:

    第一行一个整数 n,表示字符串集合中字符串的个数
    接下来每行一个字符串

    输出格式:

    一个整数,表示有多少不同的“好”的字符串

    样例输入:

    2
    ab
    ac

    样例输出:

    9

    数据范围:

    对于 20%的数据,1 <= n <= 200
    对于 50%的数据,1 <= n <= 2000
    对于 100%的数据,1 <= n <= 10000,每个字符串非空且长度不超过 30,均为小写字母组成。

    时间限制:

    3s

    空间限制:

    512m
     
    这是一道AC自动机的题.
    我订题时,发现我的写法与大家的不一样.
    别人是减去fail树上子树大小减一.
    我是另一种写法.
    对每个前缀找后缀相等的,长度比他短的另一前缀是否存在(即fail)
    存在的话,ans-前缀集合中后缀为上文两前缀的前缀个数.
    这竟然和fail子树大小等价!!!
    玄学! 疑问尚未解决.
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<iostream>
    using namespace std;
    char a[1000010],s[1000010];
    long long ans;
    int sz,n;
    int ch[1000010][26],f[1000010],v[1000010],val[1000010],fa[1000010],dep[1000100],tag[1000010];
    void init(){
        sz=0; ans=0;
        memset(ch[0],0,sizeof(ch[0]));
        memset(f,0,sizeof(f));
        memset(v,0,sizeof(v));
    }
    void insert(char *t,int p){
        int x=0;
        for (int i=0; t[i]; i++){
            int y=t[i]-'a';
            if (!ch[x][y]){
                ch[x][y]=++sz;
                dep[sz]=dep[x]+1;
                fa[sz]=x;
                memset(ch[sz],0,sizeof(ch[sz]));
            }
            x=ch[x][y];
        }
    }
    void getfail(){
        queue<int> q;    
        f[0]=0;
        for (int i=0; i<=25; i++) if (ch[0][i]) q.push(ch[0][i]);
        while (!q.empty()){
            int x=q.front();
            q.pop();
            for (int i=0; i<=25; i++){
                int    *y=&ch[x][i],*z=&ch[f[x]][i];
                if (!(*y)){
                    (*y)=(*z);
                    continue;
                }
                q.push(*y);
                f[*y]=(*z);
            }
        }
    }
    void re(int orz){
        int x=orz;
        while (f[x]){
            x=f[x];
            int f=orz,t=dep[x];
            while (t--) f=fa[f];
            ++tag[f];
            break;//?
        }
    }
    void calc(int orz){
        int x=orz;
        while (f[x]){
            x=f[x];
            ans-=tag[x];
        }
    }
    int main(){
        scanf("%d",&n);
        init();
        for (int i=1; i<=n; i++){
            scanf("%s",a);
            insert(a,i);
        }
        ans=1ll*sz*sz;
        getfail();
    //    for (int i=1; i<=sz; ++i) cerr<<last[i]<<" "; cerr<<endl;
    //    for (int i=1; i<=sz; ++i) cerr<<dep[i]<<" "; cerr<<endl;
        for (int i=1; i<=sz; ++i) re(i);
    //    for (int i=1; i<=sz; ++i) cerr<<tag[i]<<" "; cerr<<endl;
    //    for (int i=1; i<=sz; ++i) cerr<<val[i]<<" "; cerr<<endl;
        for (int i=1; i<=sz; ++i) calc(i);
        printf("%lld",ans);
        return 0;
    }

    有待思考.

  • 相关阅读:
    python中的线程(zz)
    Bzoj1014 外星人Prefix
    ABC
    终于明白阿里百度这样的大公司,为什么面试经常拿ThreadLocal考验求职者了
    我去面试没带简历,你让我走人?
    利用Python框架pyxxnet_project实现的网络服务
    我以为我对Mysql索引很了解,直到我遇到了阿里的面试官
    CSS必备知识大全
    致 Python 初学者
    从入门到精通,Java学习路线导航
  • 原文地址:https://www.cnblogs.com/Yuhuger/p/8585590.html
Copyright © 2020-2023  润新知