• 回文树专题


    学习链接:http://axuhongbo.top/tree/

    /*---------------------------------------------

    1.len[i]表示编号为i的节点表示的回文串的长度(一个节点表示一个回文串)

    2.next[i][c]表示编号为i的节点表示的回文串在两边添加字符c以后变成的回文串的编号(和字典树类似)。

    3.fail[i]表示节点i失配以后跳转不等于自身的节点i表示的回文串的最长后缀回文串(和AC自动机类似)。

    4.cnt[i]表示节点i表示的本质不同的串的个数(从根节点到当前节点形成的字符串的出现次数)

    5.num[i]表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数。(以i为最终节点,往前形成的子串中是回文串的个数。举个例子:babbab,ba是一个,bab是一个。babbba又是一个,所以当num[i]表示以b为结尾的时候,num[i]=3)

    6.last指向新添加一个字母后所形成的最长回文串表示的节点。

    7.S[i]表示第i次添加的字符(一开始设S[0] = -1(可以是任意一个在串S中不会出现的字符))。

    8.p表示添加的节点个数。

    9.n表示添加的字符个数。

    ------------------------------------*/

    专题链接:https://cn.vjudge.net/contest/283852#overview

    A - The Problem to Slow Down You

    题目大意:给你两个字符串,然后问你两个字符串中公共的回文串的数目。

    具体思路:首先对第一个字符串进行建树,记录一下每一个本质不同的回文串的个数,然后再对第二个字符串进行操作,数还是按照第一个字符串建好的树进行计数,然后数一下这个字符串在原来的树上形成的回文串的个数,然后两个个数分别相乘累加就可以了。

    AC代码:

      1 #include<iostream>
      2 #include<stack>
      3 #include<cstring>
      4 #include<iomanip>
      5 #include<stdio.h>
      6 #include<algorithm>
      7 #include<cmath>
      8 using namespace std;
      9 # define ll long long
     10 # define inf 0x3f3f3f3f
     11 const int maxn = 4e5+100;
     12 char str1[maxn];
     13 char str2[maxn];
     14 struct Palindromic_Tree
     15 {
     16     int nex[maxn][30];
     17     int fail[maxn];
     18     ll cnt1[maxn],cnt2[maxn];
     19     int num[maxn];
     20     int len[maxn];
     21     int s[maxn];
     22     int last,len1,len2;
     23     int n;
     24     int p;
     25     int newnode(int l)
     26     {
     27         for(int i=0; i<30; i++)
     28             nex[p][i]=0;
     29         num[p]=0;
     30         len[p]=l;
     31         return p++;
     32     }
     33     void init()
     34     {
     35         for(int i=0;i<=len1+len2+4;i++){
     36         cnt1[i]=cnt2[i]=0;
     37         }
     38         p=0;
     39         newnode(0);
     40         newnode(-1);
     41         last=0;
     42         n=0;
     43         s[n]=-1;
     44         fail[0]=1;
     45     }
     46     void init1()
     47     {
     48         last=0;
     49         n=0;
     50         s[n]=-1;
     51         fail[0]=1;
     52     }
     53     int getfail(int x)
     54     {
     55         while(s[n-len[x]-1]!=s[n])
     56             x=fail[x];
     57         return x;
     58     }
     59     void add(int c)
     60     {
     61         c-='a';
     62         s[++n]=c;
     63         int cur=getfail(last);
     64         if(!nex[cur][c])
     65         {
     66             int now=newnode(len[cur]+2);
     67             fail[now]=nex[getfail(fail[cur])][c];
     68             nex[cur][c]=now;
     69             num[now]=num[fail[now]]+1;
     70         }
     71         last=nex[cur][c];
     72         cnt1[last]++;
     73     }
     74     void add1(int c)
     75     {
     76         c-='a';
     77         s[++n]=c;
     78         int cur=getfail(last);
     79         if(!nex[cur][c])
     80         {
     81             int now=newnode(len[cur]+2);
     82             fail[now]=nex[getfail(fail[cur])][c];
     83             nex[cur][c]=now;
     84             num[now]=num[fail[now]]+1;
     85         }
     86         last=nex[cur][c];
     87         cnt2[last]++;
     88     }
     89     void count1()
     90     {
     91         for(int i=p-1; i>=0; i--)
     92             cnt1[fail[i]]+=cnt1[i];
     93     }
     94     void count2()
     95     {
     96         for(int i=p-1; i>=0; i--)
     97         {
     98             cnt2[fail[i]]+=cnt2[i];
     99         }
    100     }
    101 } q;
    102 int main()
    103 {
    104     int T;
    105     int Case=0;
    106     scanf("%d",&T);
    107     while(T--)
    108     {
    109         scanf("%s",str1);
    110         scanf("%s",str2);
    111         q.len1=strlen(str1);
    112         q.len2=strlen(str2);
    113         q.init();
    114         for(int i=0; i<q.len1; i++)
    115         {
    116             q.add(str1[i]);
    117         }
    118         q.init1();
    119         for(int i=0; i<q.len2; i++)
    120         {
    121             q.add1(str2[i]);
    122         }
    123         q.count1();
    124         q.count2();
    125         ll ans=0;
    126         printf("Case #%d: ",++Case);
    127         for(int i=2; i<=q.p-1; i++)
    128         {
    129             ans+=q.cnt1[i]*q.cnt2[i];
    130         }
    131         printf("%lld
    ",ans);
    132     }
    133     return 0;
    134 }

    B - 最长回文

    题目大意:让你求给定的字符串中最长的回文字符子串。

    具体思路:每插入一个字符,求插入的以这个字符结尾形成的最长的回文子串就可以了。

    AC代码:

     1 #include<iostream>
     2 #include<stack>
     3 #include<cstring>
     4 #include<iomanip>
     5 #include<stdio.h>
     6 #include<algorithm>
     7 #include<cmath>
     8 using namespace std;
     9 # define ll long long
    10 # define inf 0x3f3f3f3f
    11 const int maxn = 2e5+100;
    12 char str[maxn];
    13 struct Palindromic_Tree
    14 {
    15     int nex[maxn][30];
    16     int fail[maxn];
    17     ll cnt[maxn];
    18     int num[maxn];
    19     int len[maxn];
    20     int s[maxn];
    21     int last;
    22     int n;
    23     int p;
    24     int newnode(int l)
    25     {
    26         for(int i=0; i<30; i++)
    27             nex[p][i]=0;
    28         cnt[p]=0;
    29         num[p]=0;
    30         len[p]=l;
    31         return p++;
    32     }
    33     void init()
    34     {
    35         p=0;
    36         newnode(0);
    37         newnode(-1);
    38         last=0;
    39         n=0;
    40         s[n]=-1;
    41         fail[0]=1;
    42     }
    43     int getfail(int x)
    44     {
    45         while(s[n-len[x]-1]!=s[n])
    46             x=fail[x];
    47         return x;
    48     }
    49     void add(int t,int c)
    50     {
    51         c-='a';
    52         s[++n]=c;
    53         int cur=getfail(last);
    54       //  cout<<t<<" "<<cur<<endl;
    55         if(!nex[cur][c])
    56         {
    57             int now=newnode(len[cur]+2);
    58             fail[now]=nex[getfail(fail[cur])][c];
    59         //    cout<<cur<<" "<<fail[cur]<<endl;
    60         //    cout<<11111<<" "<<getfail(fail[cur])<<endl;
    61             nex[cur][c]=now;
    62             num[now]=num[fail[now]]+1;
    63         }
    64         last=nex[cur][c];
    65         cnt[last]++;
    66     }
    67     void cont()
    68     {
    69         for(int i=p-1; i>=0; i--)
    70             cnt[fail[i]]+=cnt[i];
    71     }
    72 } q;
    73 int main()
    74 {
    75     int T;
    76     scanf("%d",&T);
    77     while(~scanf("%s",str))
    78     {
    79         int maxx=0;
    80         int len=strlen(str);
    81         q.init();
    82         for(int i=0; i<len; i++)
    83         {
    84             q.add(i,str[i]);
    85             maxx=max(q.len[q.last],maxx);
    86         }
    87         printf("%d
    ",maxx);
    88     }
    89     return 0;
    90 }

    C - The Number of Palindromes

    题目大意:给你一个字符串,让你求这个字符串中本质不同的回文串的个数(长度不同,或者长度相同回文串排布不完全相同)。

    具体思路:回文树中p-2就是本质不同的回文串的个数,因为如果有重复的就一定能用形成的回文树表示。

    AC代码:

     1 #include<iostream>
     2 #include<stack>
     3 #include<cstring>
     4 #include<iomanip>
     5 #include<stdio.h>
     6 #include<algorithm>
     7 #include<cmath>
     8 using namespace std;
     9 # define ll long long
    10 # define inf 0x3f3f3f3f
    11 const int maxn = 2e5+100;
    12 char str[maxn];
    13 struct Palindromic_Tree
    14 {
    15     int nex[maxn][30];
    16     int fail[maxn];
    17     ll cnt[maxn];
    18     int num[maxn];
    19     int len[maxn];
    20     int s[maxn];
    21     int last;
    22     int n;
    23     int p;
    24     int newnode(int l)
    25     {
    26         for(int i=0; i<30; i++)
    27             nex[p][i]=0;
    28         cnt[p]=0;
    29         num[p]=0;
    30         len[p]=l;
    31         return p++;
    32     }
    33     void init()
    34     {
    35         p=0;
    36         newnode(0);
    37         newnode(-1);
    38         last=0;
    39         n=0;
    40         s[n]=-1;
    41         fail[0]=1;
    42     }
    43     int getfail(int x)
    44     {
    45         while(s[n-len[x]-1]!=s[n])
    46             x=fail[x];
    47         return x;
    48     }
    49     void add(int t,int c)
    50     {
    51         c-='a';
    52         s[++n]=c;
    53         int cur=getfail(last);
    54       //  cout<<t<<" "<<cur<<endl;
    55         if(!nex[cur][c])
    56         {
    57             int now=newnode(len[cur]+2);
    58             fail[now]=nex[getfail(fail[cur])][c];
    59         //    cout<<cur<<" "<<fail[cur]<<endl;
    60         //    cout<<11111<<" "<<getfail(fail[cur])<<endl;
    61             nex[cur][c]=now;
    62             num[now]=num[fail[now]]+1;
    63         }
    64         last=nex[cur][c];
    65         cnt[last]++;
    66     }
    67     void cont()
    68     {
    69         for(int i=p-1; i>=0; i--)
    70             cnt[fail[i]]+=cnt[i];
    71     }
    72 } q;
    73 int main()
    74 {
    75     int T;
    76     scanf("%d",&T);
    77     while(~scanf("%s",str))
    78     {
    79         int maxx=0;
    80         int len=strlen(str);
    81         q.init();
    82         for(int i=0; i<len; i++)
    83         {
    84             q.add(i,str[i]);
    85             maxx=max(q.len[q.last],maxx);
    86         }
    87         printf("%d
    ",maxx);
    88     }
    89     return 0;
    90 }

    D - 最长双回文串

     题目大意:顺序和逆序读起来完全一样的串叫做回文串。比如 acbca 是回文串,而 abc 不是( abc 的顺序为“abc” ,逆序为 “cba” ,不相同)。 
    输入长度为 n 的串 S ,求 S 的最长双回文子串 T, 即可将 T 分为两部分 X , Y ,( |X|,|Y|≥1 )且 X 和 Y 都是回文串。然后给你一个字符串,让你找出这个字符串中的最的双回文串。

    具体思路:我们枚举每一个位置,最长的双回文串的形成是以i为结尾的回文串+以i+1为开头的回文串,在找以i+1为开头的回文串的时候,我们将字符串倒过来再建一遍树就可以了。我们枚举每一个位置,然后遍历找出最大的就可以了。

    AC代码:

     1 #include<iostream>
     2 #include<stack>
     3 #include<cstring>
     4 #include<iomanip>
     5 #include<stdio.h>
     6 #include<algorithm>
     7 #include<cmath>
     8 using namespace std;
     9 # define ll long long
    10 # define inf 0x3f3f3f3f
    11 const int maxn = 4e5+100;
    12 char str[maxn];
    13 struct Palindromic_Tree
    14 {
    15     int nex[maxn][30];
    16     int fail[maxn];
    17     ll cnt[maxn];
    18     int num[maxn];
    19     int len[maxn];
    20     int s[maxn];
    21     int pre[maxn];
    22     int last;
    23     int n;
    24     int p;
    25     int newnode(int l)
    26     {
    27         for(int i=0; i<30; i++)
    28             nex[p][i]=0;
    29         num[p]=0;
    30         len[p]=l;
    31         return p++;
    32     }
    33     void init()
    34     {
    35         p=0;
    36         newnode(0);
    37         newnode(-1);
    38         last=0;
    39         n=0;
    40         s[n]=-1;
    41         fail[0]=1;
    42     }
    43     int getfail(int x)
    44     {
    45         while(s[n-len[x]-1]!=s[n])
    46             x=fail[x];
    47         return x;
    48     }
    49     void add(int c,int i)
    50     {
    51         c-='a';
    52         s[++n]=c;
    53         int cur=getfail(last);
    54         if(!nex[cur][c])
    55         {
    56             int now=newnode(len[cur]+2);
    57             fail[now]=nex[getfail(fail[cur])][c];
    58             nex[cur][c]=now;
    59             num[now]=num[fail[now]]+1;
    60         }
    61         last=nex[cur][c];
    62         pre[i]=len[last];
    63     }
    64 } q1,q2;
    65 int main()
    66 {
    67 q1.init();
    68 q2.init();
    69 scanf("%s",str+1);
    70 int len=strlen(str+1);
    71 for(int i=1;i<=len;i++){
    72 q1.add(str[i],i);
    73 }
    74 reverse(str+1,str+len+1);
    75 for(int i=1;i<=len;i++){
    76 q2.add(str[i],i);
    77 }
    78 int maxx=0;
    79 for(int i=1;i<len;i++){
    80         if(maxx<q1.pre[i]+q2.pre[len-i])
    81         cout<<i<<endl;
    82 maxx=max(maxx,q1.pre[i]+q2.pre[len-i]);
    83 }
    84 printf("%d
    ",maxx);
    85     return 0;
    86 }
  • 相关阅读:
    5. Redis持久化
    4.Redis客户端
    3.Redis高级功能
    2.Redis五种数据结构
    1.Redis简介
    32.Mysql Cluster
    suffix ACM-ICPC 2017 Asia Qingdao
    多层BFS
    我想和你们说说java和C++___C加加
    11073 最热门的K个搜索串
  • 原文地址:https://www.cnblogs.com/letlifestop/p/10397314.html
Copyright © 2020-2023  润新知