zoukankan      html  css  js  c++  java
  • 寻找好串

    1709:寻找好串

    时间限制: 2000 ms         内存限制: 262144 KB

    【题目描述】

    有一个字符串集合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,均为小写字母组成。

    【题解】

    首先发现如果没有相同的好串,答案为cnt*cnt。

    对于两个构造出来相同的串,则有一个串是前一个的前缀,第二个串是另一个的后缀。

    那么我们可以找出每一个前缀和它最长的后缀的非公共部分,求出作为几个前缀的后缀(该串作为后缀有几个重复),减去该数即为答案。

    代码如下:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int N=3e5+5;
    int n,sum[N],cnt,ans,ren[N],ru[N];
    char c[35];
    struct trie
    {
        int er[26],fail,fa;
    }a[N];
    inline void insert()
    {
        int len=strlen(c+1),now=0;
        for(int i=1;i<=len;i++)
        {
            if(!a[now].er[c[i]-'a']) a[now].er[c[i]-'a']=++cnt;
            a[a[now].er[c[i]-'a']].fa=now;
            now=a[now].er[c[i]-'a'];
        }
    }
    queue <int> que;
    inline void get_fail()
    {
        for(int i=0;i<=25;i++)
            if(a[0].er[i])
                que.push(a[0].er[i]);
        while(!que.empty())
        {
            int now=que.front();que.pop();
            ru[a[now].fail]++;
            for(int i=0;i<=25;i++)
            {
                if(a[now].er[i])
                {
                    a[a[now].er[i]].fail=a[a[now].fail].er[i];
                    que.push(a[now].er[i]);
                }
                else 
                    a[now].er[i]=a[a[now].fail].er[i];
            }
        }
    }
    inline void get_sum()
    {
        for(int i=0;i<=cnt;i++)
            if(ru[i]==0)
                que.push(i);
        for(int i=0;i<=cnt;i++) ren[i]=1;
        while(!que.empty())
        {
            int now=que.front();que.pop();
            ren[a[now].fail]+=ren[now];
            sum[now]=ren[now]-1;
            ru[a[now].fail]--;
            if(ru[a[now].fail]==0) que.push(a[now].fail);
        }
    }
    signed main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",c+1);
            insert(); 
        }
        get_fail();
        get_sum();
        ans=cnt*cnt;
        for(int i=0;i<=cnt;i++)
            if(a[i].fail)
            {
                int hu1=i,hu2=a[i].fail;
                while(hu2)
                {
                    hu1=a[hu1].fa;
                    hu2=a[hu2].fa;
                }    //
                ans-=sum[hu1];
            }
        cout<<ans;
        return 0;
    } 
    View Code
  • 相关阅读:
    linux 权限管理命令
    大三上学期总结
    C# 读写Excel的一些方法,Aspose.Cells.dll
    Topshelf 创建.net服务整理和安装步骤(转)
    你必须知道的.NET之特性和属性(转)
    用SQL语句删除一个数据库的所有表和所有存储过程
    System.DllNotFoundException: 无法加载 DLL“FileTracker.dll”: 动态链接库(DLL)初始化例
    关于消息队列的使用[转]
    PhpStorm使用技巧小结
    转载]C#实现获取浏览器信息
  • 原文地址:https://www.cnblogs.com/betablewaloot/p/12158578.html
Copyright © 2011-2022 走看看