zoukankan      html  css  js  c++  java
  • 回文树专题

    学习链接: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 }
  • 相关阅读:
    POJ 2251 Dungeon Master
    HDU 3085 Nightmare Ⅱ
    CodeForces 1060 B Maximum Sum of Digits
    HDU 1166 敌兵布阵(树状数组)
    HDOJ 2050 折线分割平面
    HDU 5879 Cure
    HDU 1878 欧拉回路
    HDU 6225 Little Boxes
    ZOJ 2971 Give Me the Number
    HDU 2680 Choose the best route
  • 原文地址:https://www.cnblogs.com/letlifestop/p/10397314.html
Copyright © 2011-2022 走看看