• String


     

    Give you a string S,assume the Sub-String Stri = S[0..i] and the length of the string is N. e.g. S = "moreandmorecold", N = 15, Str0 = "m" Str1 = "mo" Str2 = "mor" and so on. 
    And we define c[i] indicate how many Sub-String Stri in S, now please calculate the sum of c[0] to c[N-1].
    给出一个字符串,请算出它的每个前缀分别在字符串中出现了多少次。再将这些结果加起来输出

    Input

    The first line include a number T, means the number of test cases. 
    For each test case, just a line only include lowercase indicate the String S, the length of S will less than 100000.

    Output

    For each test case, just a number means the sum.

    Sample Input

    3
    acacm
    moreandmorecold
    thisisthisththisisthisisthisththisis

    Sample Output

    7
    19
    82
    HINT
    For the first case, 
    there are two "a","ac" and one "aca","acac","acacm" in the string "acacm". 
    So the answer is 2 + 2 + 1 + 1 + 1 = 7

    sol1:先求出next[]数组值,建fail树求出每个结点为根的子树个数,加起来即为答案,具体如下:



    树中每个结点都是整个字符串的前缀,对于每条链,父亲结点既是儿子的前缀,也是后缀,我们要统计每个结点出现的次数,就是统计以该结点为根的子树的结点个数。上例中,1结点为根的子树结点数为3,即a出现了3次。我们建立fail树后,做dfs()即可求出子树大小。

    sol2:
    求出next[]后,逆循环扫一遍。

    做dfs(),我们要重复计算多次,更推荐的方法是从下往上做逆循环,这样做过的事情就不会再做。逆循环时,父亲结点编号小,儿子结点编号大,儿子结点为根的子树个数与父亲结点先计算出来。


    代码如下:
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 ll o,p[100011],sum[100011],len,ans,j;
     5 char a[100011];
     6 int main()
     7 {
     8     scanf("%lld",&o);
     9     while(o--)
    10     {
    11         memset(p,0,sizeof(p));
    12         memset(sum,0,sizeof(sum));
    13         scanf("%s",a+1);
    14         len=strlen(a+1);
    15         ans=0;j=0;
    16         for(ll i=1;i<len;i++)
    17         {
    18             while(j&&a[j+1]!=a[i+1])
    19                 j=p[j];
    20             if(a[j+1]==a[i+1])
    21                 j++;
    22             p[i+1]=j;
    23         }
    24         for (int i=1;i<=len;i++)
    25         sum[i]=1; 
    26         for(ll i=len;i>=1;i--)
    27             sum[p[i]]+=sum[i];
    28         for (int i=1;i<=len;i++)
    29             ans=ans+sum[i];
    30         printf("%lld
    ",ans);
    31     }
    32     return 0;
    33 }
    
    

    当然,也可以写成正循环,如下:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 ll o,p[100011],sum[100011],len,ans,j;
     5 char a[100011];
     6 int main()
     7 {
     8     scanf("%lld",&o);
     9     while(o--)
    10     {
    11         memset(p,0,sizeof(p));
    12         memset(sum,0,sizeof(sum));
    13         scanf("%s",a+1);
    14         len=strlen(a+1);
    15         ans=0;j=0;
    16         for(ll i=1;i<len;i++)
    17         {
    18             while(j&&a[j+1]!=a[i+1])
    19                 j=p[j];
    20             if(a[j+1]==a[i+1])
    21                 j++;
    22             p[i+1]=j;
    23         }
    24         for(ll i=1;i<=len;i++)
    25             sum[i]=sum[p[i]]+1,
    26             ans+=sum[i];
    27         printf("%lld
    ",ans);
    28     }
    29     return 0;
    30 }
     
    
    

     




  • 相关阅读:
    Python3小练习2——(汉诺塔的移动),递归
    Python3小练习1——(ax*x+ bx + c = 0的解)
    SSRS数据导出Excel多出空白列
    ETL 压缩文件(makecab) 并邮件发送
    关于System.Web.Script.Serialization命名空间的引用
    如何通过VIsual Studio安装程序修改VS2017?
    如何其他服务器能够连接自己本机的数据库?
    SSAS表格模型部署问题
    表格模型——安装实例
    Leetcode 76题:最小覆盖子串 滑动窗口经典题
  • 原文地址:https://www.cnblogs.com/cutepota/p/12555570.html
Copyright © 2020-2023  润新知