zoukankan      html  css  js  c++  java
  • 回文串 BZOJ 3676

    回文串

    【问题描述】

    考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最大出现值。 

    【输入格式】

    输入只有一行,为一个只包含小写字母(a -z)的非空字符串s。 

    【输出格式】

    输出一个整数,为逝查回文子串的最大出现值。 

    【样例输入1】

    abacaba

    【样例输入2】

    www

    【样例输出1】

    7

    【样例输出2】


    题解:

    我们先用 Manacher 找出所有本质不同的回文,即 Manacher 的每一次拓展出的回文

    对于每一个回文,我们已经知道了它的区间,即知道了长度与右区间,那么就能在 Sam 上确定它所属的 Right 的集合

    为了确定回文 [ l , r ] 所在的状态,我们记录所有有 1 - i 的字符组成的字符串所在的状态,记为 pos[i]

    那么每次查找时,从 pos[r] 开始在 Sam 的 fail 树上倍增,就能确定回文所在的状态,那么这个状态 Right 集合的大小就是回文出现的次数

    更新答案即可

      1 #include<cmath>
      2 #include<cstdio>
      3 #include<cstdlib>
      4 #include<cstring>
      5 #include<iostream>
      6 #include<algorithm>
      7 using namespace std;
      8 const int lgn = 18;
      9 const int maxn = 3e5 + 233;
     10 const int maxp = 6e5 + 233; 
     11 int n;
     12 long long ans;
     13 char s[maxn];
     14 int r[maxp];
     15 char sx[maxp];
     16 int fat[lgn + 1][maxp];
     17 struct one
     18 {
     19     int num, last;
     20     int w[maxn], si[maxp], que[maxp];
     21     int pos[maxn], maxr[maxp], fail[maxp], tran[maxp][26];
     22     inline one()
     23     {
     24         num = last = 1;
     25     }
     26     inline void ins(int i)
     27     {
     28         int anc = last, asc = s[i - 1] - 'a', now = last = ++num;
     29         pos[i] = now;
     30         si[now] = 1;
     31         maxr[now] = maxr[anc] + 1;
     32         while(anc && !tran[anc][asc]) tran[anc][asc] = now, anc = fail[anc];
     33         if(!anc) fail[now] = 1;
     34         else
     35         {
     36             int son = tran[anc][asc];
     37             if(maxr[son] == maxr[anc] + 1) fail[now] = son;
     38             else
     39             {
     40                 int rep = ++num;
     41                 maxr[rep] = maxr[anc] + 1;
     42                 memcpy(tran[rep], tran[son], sizeof(tran[rep]));
     43                 fail[rep] = fail[son];
     44                 fail[son] = fail[now] = rep;
     45                 while(tran[anc][asc] == son) tran[anc][asc] = rep, anc = fail[anc];
     46             }
     47         }
     48     }
     49     inline void size()
     50     {
     51         for(int i = 1; i <= num; ++i) ++w[maxr[i]];
     52         for(int i = 1; i <= n; ++i) w[i] += w[i - 1];
     53         for(int i = num; i >= 1; --i) que[w[maxr[i]]--] = i;
     54         for(int i = num; i >= 1; --i) si[fail[que[i]]] += si[que[i]];
     55     }
     56     inline void rmq()
     57     {
     58         for(int i = 1; i <= num; ++i) fat[0][i] = fail[i];
     59         for(int k = 1; k <= lgn; ++k)
     60             for(int i = 1; i <= num; ++i)
     61                 fat[k][i] = fat[k - 1][fat[k - 1][i]];
     62     }
     63 };
     64 one sam;
     65 inline void Sam()
     66 {
     67     for(int i = 0; i < n; ++i) sam.ins(i + 1);
     68     sam.size();
     69     sam.rmq();
     70 }
     71 inline void Solve(int l, int r)
     72 {
     73     int x = sam.pos[r], len = r - l + 1;
     74     for(int i = lgn; i >= 0; --i)
     75         if(sam.maxr[fat[i][x]] >= len) x = fat[i][x];
     76     ans = max(ans, (long long) sam.si[x] * len);
     77 }
     78 inline void Manacher()
     79 {
     80     int m = 0;
     81     sx[0] = '*';
     82     for(int i = 0; i < n; ++i) sx[++m] = s[i], sx[++m] = '#';
     83     sx[m] = '+';
     84     int id = 0, mx = 0;
     85     for(int i = 1; i < m; ++i)
     86     {
     87         if(mx > i) r[i] = min(r[(id << 1) - i], mx - i + 1);
     88         while(sx[i + r[i]] == sx[i - r[i]])
     89         {
     90             if(sx[i + r[i]] != '#') Solve((i - r[i] >> 1) + 1, (i + r[i] >> 1) + 1);
     91             else Solve((i - r[i] + 1 >> 1) + 1, (i + r[i] - 1 >> 1) + 1);
     92             ++r[i];
     93         }
     94         if(i + r[i] - 1 > mx) mx = i + r[i] - 1, id = i;
     95     }
     96 }
     97 int main()
     98 {
     99     scanf("%s", s);
    100     n = strlen(s);
    101     Sam();
    102     Manacher();
    103     printf("%lld", ans);
    104 }
  • 相关阅读:
    基于智能学习与业务感知的工控安全监测体系建设
    深度解析工控网络流量特点
    Studio 从入门到精通 (一)
    AndroidStudio权威教程 AS添加第三方库的6种方式(Jar module so等)
    最全的资源教程-前端涉及的所有知识体系
    Android 屏幕适配(二)增强版百分比布局库(percent-support-lib)
    Android 屏幕适配(一)百分比布局库(percent-support-lib) 解析与扩展
    Android 手势识别类 ( 三 ) GestureDetector 源码浅析
    Android 手势识别类 ( 二 ) GestureDetector 源码浅析
    Android 手势识别类 ( 一 ) GestureDetector 基本介绍
  • 原文地址:https://www.cnblogs.com/lytccc/p/6748436.html
Copyright © 2011-2022 走看看