• 串 2016Vijos省选集训 day3[AC自动机]


    1、串(string.c/.cpp/.pas)

    限时1s,内存限制256MB,20个测试点

     

    【题目描述】

    兔子们在玩字符串的游戏。首先,它们拿出了一个字符串集合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,均为小写字母组成。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    
    #ifdef WIN32
    #define LL "%I64d"
    #else
    #define LL "%lld"
    #endif 
    #define FRE(name) freopen(#name".in","r",stdin);freopen(#name".out","w",stdout);
    #define FC fclose(stdin);fclose(stdout);
    
    typedef long long ll;
    const int N=3e5+5;
    
    int n,L,len,cnt,tr[N][26],d[N][26],num[N],fail[N],q[N];
    char s[32];
    ll ans,f[32][N];
    void insert(){
        int now=1;
        for(int i=0;i<len;i++){
            int t=s[i]-'a';
            if(!tr[now][t]) tr[now][t]=++cnt,num[cnt]=num[now]+1;
            now=tr[now][t];
        }
    }
    void AC_mach(){
        int h=0,t=1;int p;
        q[1]=1;fail[1]=0;
        while(h!=t){
            int now=q[++h];
            for(int i=0;i<26;i++){
                if(tr[now][i]){
                    p=fail[now];
                    while(!tr[p][i]) p=fail[p];
                    fail[tr[now][i]]=tr[p][i];
                    q[++t]=tr[now][i];
                }
                else{
                    p=fail[now];
                    while(!tr[p][i]) p=fail[p];
                    tr[now][i]=tr[p][i];
                    d[now][i]=1;
                }
            }
        }
    }
    void first(){
        cnt=1;ans=0;
        for(int i=0;i<26;i++) tr[0][i]=1;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%s",s);
            len=strlen(s);
            L=max(L,len);
            insert();
        }
    }
    void solve(){
        AC_mach();
        for(int i=2;i<=cnt;i++){
            if(fail[i]!=1) ans++;
            for(int j=0;j<26;j++){
                if(tr[i][j]!=1&&d[i][j]){
                    f[1][tr[i][j]]++;
                }
            }
        }
        for(int i=1;i<=L;i++){
            for(int j=2;j<=cnt;j++){
                if(f[i][j]){
                    ans+=f[i][j];
                    for(int k=0;k<26;k++){
                        if(num[tr[j][k]]>=i+1){
                            f[i+1][tr[j][k]]+=f[i][j];
                        }
                    }
                }
            }
        }
        printf(LL,ans);
    }
    int main(){
        FRE(string)
        first();
        solve();
        FC
        return 0;
    }
  • 相关阅读:
    脚本——猜拳
    脚本——基础命令
    脚本——1-100奇数的和
    脚本——判断文件类型
    脚本——判断分数是否合格
    脚本——判断服务是否开启
    脚本——ping一个网址三次
    脚本——判断是否root用户
    脚本——查看目录是否存在
    第十八天:CSV、JSON、Excel、SQLite
  • 原文地址:https://www.cnblogs.com/shenben/p/6398010.html
Copyright © 2020-2023  润新知