• Panlindromic Tree(回文树)的四个例题


    http://www.tsinsen.com/new/A1280 

    双回文串,正着做一遍,倒着做一遍,维护每个节点 向前向后的最长回文子串长度(len[ last ])

     1 #include <bits/stdc++.h>
     2 const long long mod = 1e9+7;
     3 const double ex = 1e-10;
     4 #define inf 0x3f3f3f3f
     5 using namespace std;
     6 const int MAXN = 212345;
     7 const int N = 26;
     8 struct Palindromic_Tree{
     9     int next[MAXN][N];
    10     int fail[MAXN];
    11     int cnt[MAXN];
    12     int num[MAXN];
    13     int len[MAXN];
    14     int S[MAXN];
    15     int last;
    16     int n;
    17     int p;
    18     int newnode(int l){
    19         for (int i = 0 ; i<N; i++) next[p][i] = 0;
    20         cnt[p] = 0;
    21         num[p] = 0;
    22         len[p] = l;
    23         return p++;
    24     }
    25     void init(){
    26         p = 0;
    27         newnode(0);
    28         newnode(-1);
    29         last = 0;
    30         n  = 0;
    31         S[n] = -1;
    32         fail[0] = 1;
    33     }
    34     int get_fail(int x){
    35         while (S[n-len[x]-1] != S[n]) x = fail[x];
    36         return x;
    37     }
    38     int add(int c){
    39         c-='a';
    40         S[++n] = c;
    41         int cur = get_fail(last);
    42         if (!next[cur][c]){
    43             int now = newnode(len[cur] + 2);
    44             fail[now] = next[get_fail(fail[cur])][c];
    45             next[cur][c] = now;
    46             num[now] = num[fail[now]] + 1;
    47         }
    48         last = next[cur][c];
    49         cnt[last]++;
    50         return len[last];
    51     }
    52     void count(){
    53         for (int i = p-1  ; i >= 0; i--) cnt[fail[i]] += cnt[i];
    54     }
    55 };
    56 Palindromic_Tree a;
    57 int len[212345];
    58 int main()
    59 {
    60     string s;
    61     cin >> s;
    62     int l = s.length();
    63     a.init();
    64     for (int i = 0 ; i<l ; i++){
    65         len[i] = a.add(s[i]);
    66     }
    67     a.init();
    68     int ans = 0;
    69     for (int i = l-1; i>=1 ;i--){
    70         ans = max(ans , len[i-1] + a.add(s[i]));
    71     }
    72     cout << ans << endl;
    73     return 0;
    74 }
    View Code

    http://www.tsinsen.com/new/A1255

    可以把每种串的 数目和长度存下来,按照长度排个序,从大到小维护。

     1 #include <bits/stdc++.h>
     2 const long long mod = 19930726;
     3 const double ex = 1e-10;
     4 #define inf 0x3f3f3f3f
     5 using namespace std;
     6 const int MAXN = 2123456;
     7 const int N = 26;
     8 struct Palindromic_Tree{
     9     int next[MAXN][N];
    10     int fail[MAXN];
    11     int cnt[MAXN];
    12     int num[MAXN];
    13     int len[MAXN];
    14     int S[MAXN];
    15     int last;
    16     int n;
    17     int p;
    18     int newnode(int l){
    19         for (int i = 0 ; i<N; i++) next[p][i] = 0;
    20         cnt[p] = 0;
    21         num[p] = 0;
    22         len[p] = l;
    23         return p++;
    24     }
    25     void init(){
    26         p = 0;
    27         newnode(0);
    28         newnode(-1);
    29         last = 0;
    30         n  = 0;
    31         S[n] = -1;
    32         fail[0] = 1;
    33     }
    34     int get_fail(int x){
    35         while (S[n-len[x]-1] != S[n]) x = fail[x];
    36         return x;
    37     }
    38     void add(int c){
    39         c-='a';
    40         S[++n] = c;
    41         int cur = get_fail(last);
    42         if (!next[cur][c]){
    43             int now = newnode(len[cur] + 2);
    44             fail[now] = next[get_fail(fail[cur])][c];
    45             next[cur][c] = now;
    46             num[now] = num[fail[now]] + 1;
    47         }
    48         last = next[cur][c];
    49         cnt[last]++;
    50     }
    51     void count(){
    52         for (int i = p-1  ; i >= 0; i--) cnt[fail[i]] += cnt[i];
    53     }
    54 };
    55 Palindromic_Tree a;
    56 int len[212345];
    57 typedef pair<int,long long> pii;
    58 pii p[1000022];
    59 long long ksm(long long x,long long y){
    60     long long ans = 1;
    61     while (y){
    62         if (y % 2) ans = ans * x % mod;
    63         x = x*x % mod;
    64         y/=2;
    65     }
    66     return ans;
    67 }
    68 int main()
    69 {
    70     string s;
    71     int l;
    72     long long k;
    73     cin >> l >> k;
    74     cin >> s;
    75     a.init();
    76     for (int i = 0 ; i<l ; i++){
    77         a.add(s[i]);
    78     }
    79     a.count();
    80     int cnt = 0;
    81     for (int i = 2 ; i<a.p ; i++){
    82         if (a.len[i] % 2 == 0) continue;
    83         p[cnt++] = make_pair(a.len[i],(long long)a.cnt[i]);
    84     }
    85     sort(p,p+cnt);
    86     long long ans = 1;
    87     int i = cnt-1;
    88     while (k > 0 && i >= 0){
    89         ans = (ans * ksm((long long)p[i].first,min(p[i].second,k))) % mod;
    90         k -= min(k,p[i].second);
    91         i--;
    92     }
    93     if (k > 0){
    94         puts("-1");
    95     }
    96     else cout << ans << endl;
    97 }
    View Code

    http://www.tsinsen.com/new/A1393

    这个题还是CF的17E,貌似回文树不是正解,可能需要马拉车优雅的过,明天学学马拉车写了他吧。

    这个题,第一次理解了num的含义,num记录的是每一类回文串的①性质不同,②结尾相同(左对齐)的子串数目。

    其中限制条件 性质不同  可以有多种理解,他们 长度 不同 且 左对齐,显然他们性质不同

    另外还有,以某个节点为 右端点的所有回文子串 肯定 性质不同。

    让求相交的回文串对数 , 可以 反着求,求出总的对数,减去不相交的即可。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <string>
     4 #include <algorithm>
     5 #include <iostream>
     6 const long long mod = 51123987;
     7 const double ex = 1e-10;
     8 #define inf 0x3f3f3f3f
     9 using namespace std;
    10 const int MAXN = 2000009;
    11 const int N = 26;
    12 struct Palindromic_Tree{
    13     int next[MAXN][N];
    14     int fail[MAXN];
    15     int cnt[MAXN];
    16     int num[MAXN];
    17     int len[MAXN];
    18     short S[MAXN];
    19     int last;
    20     int n;
    21     int p;
    22     int newnode(int l){
    23         for (int i = 0 ; i<N; i++) next[p][i] = 0;
    24         cnt[p] = 0;
    25         num[p] = 0;
    26         len[p] = l;
    27         return p++;
    28     }
    29     void init(){
    30         p = 0;
    31         newnode(0);
    32         newnode(-1);
    33         last = 0;
    34         n  = 0;
    35         S[n] = -1;
    36         fail[0] = 1;
    37     }
    38     int get_fail(int x){
    39         while (S[n-len[x]-1] != S[n]) x = fail[x];
    40         return x;
    41     }
    42     int add(int c){
    43         c-='a';
    44         S[++n] = c;
    45         int cur = get_fail(last);
    46         if (!next[cur][c]){
    47             int now = newnode(len[cur] + 2);
    48             fail[now] = next[get_fail(fail[cur])][c];
    49             next[cur][c] = now;
    50             num[now] = num[fail[now]] + 1;
    51         }
    52         last = next[cur][c];
    53         cnt[last]++;
    54         return num[last];
    55     }
    56     long long count(){
    57         for (int i = p-1  ; i >= 0; i--) cnt[fail[i]] += cnt[i];
    58         long long ans = 0;
    59         for (int i = 2 ; i<p;i++)
    60             ans = (ans + cnt[i])% mod;
    61         return ans;
    62     }
    63 };
    64 Palindromic_Tree a;
    65 int sum[2000009];
    66 int main()
    67 {
    68     string s;
    69     int l;
    70     cin >> l;
    71     cin >> s;
    72     a.init();
    73     for (int i = 0 ; i<l ; i++){
    74         sum[i] = a.add(s[i]);
    75     }
    76     for (int i = 1 ; i<l ;i++){
    77         sum[i] = (sum[i] + sum[i-1]) % mod;
    78     }
    79     long long ans = a.count();
    80     ans = ans * (ans - 1 ) / 2 % mod;
    81     a.init();
    82     for (int i = l-1; i>0 ; i--){
    83         long long x = a.add(s[i]);
    84         ans = ((ans - x * sum[i-1]) % mod + mod) % mod;
    85     }
    86     cout << ans << endl;
    87     return 0;
    88 }
    View Code

    卡内存卡到死,CF根本过不去,tsinsen也是卡过的。

    不过这个题让我深刻理解了num数组的含义

    还有一题之前写过的

    http://www.cnblogs.com/HITLJR/p/7687885.html

    学习回文树,首先把代码看懂,找几个简单的自己模拟一下整个过程,然后理解每个数组的含义,灵活运用add的返回值求一些东西。

  • 相关阅读:
    05--STL序列容器(List和Forward_list)
    04--STL序列容器(Stack和Queue)
    03--STL序列容器(Deque)
    STL迭代器iterator
    02--STL序列容器(Vector)
    C++回顾day03---<string字符串操作>
    C++回顾day03---<输入输出流>
    C++回顾day03---<异常>
    16位结构的CPU,8086给出物理地址的方法
    初识STM32固件库
  • 原文地址:https://www.cnblogs.com/HITLJR/p/7739510.html
Copyright © 2020-2023  润新知