zoukankan      html  css  js  c++  java
  • 【BZOJ 3676】 3676: [Apio2014]回文串 (SAM+Manacher+倍增)

    3676: [Apio2014]回文串

    Time Limit: 20 Sec  Memory Limit: 128 MB
    Submit: 2343  Solved: 1031

    Description

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

    Input

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

    Output


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

    Sample Input

    【样例输入l】
    abacaba

    【样例输入2]
    www

    Sample Output

    【样例输出l】
    7

    【样例输出2]
    4

    HINT



    一个串是回文的,当且仅当它从左到右读和从右到左读完全一样。 

    在第一个样例中,回文子串有7个:a,b,c,aba,aca,bacab,abacaba,其中: 

    ● a出现4次,其出现值为4:1:1=4 

    ● b出现2次,其出现值为2:1:1=2 

    ● c出现1次,其出现值为l:1:l=l 

    ● aba出现2次,其出现值为2:1:3=6 

    ● aca出现1次,其出现值为1=1:3=3 

    ●bacab出现1次,其出现值为1:1:5=5 

    ● abacaba出现1次,其出现值为1:1:7=7 

    故最大回文子串出现值为7。 

    【数据规模与评分】 

    数据满足1≤字符串长度≤300000。

    Source

    【分析】

      听说回文自动机可以秒掉这题,以后再学吧。

      用串建SAM,然后求出right数组。

      manacher告诉我们,本质不同的回文串最多n个,只有在mx变的时候可能增加一个回文串。

      用manacher求出所有本质不同的回文串,然后在SAM上问。

      那就是问[L,R]这个区间的子串出现了多少次【感觉这个用后缀数组的话是nlogn^2的

      从SAM的pre边相当于AC自动机上的fail,形成一棵树,pre树上倍增即可。

      就是从POS[R]开始跳,当他代表的子串的长度大于r-l+1,即可计入答案,当然子串长度越小越好(更有可能出现最多次)

      【记得拓扑序

      【啊。。。卡空间。。

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 using namespace std;
      7 #define Maxn 301000
      8 #define LL long long
      9 
     10 // int mymax(int x,int y) {return x>y?x:y;}
     11 LL mymax(LL x,LL y) {return x>y?x:y;}
     12 int mymin(int x,int y) {return x<y?x:y;}
     13 
     14 LL ans=0;
     15 
     16 struct node
     17 {
     18     int pre,step,son[30],rt;
     19 }t[2*Maxn];int last,tot;
     20 int v[2*Maxn],q[2*Maxn],pos[2*Maxn];
     21 
     22 int ff[2*Maxn][19];
     23 void get_f()
     24 {
     25     for(int i=1;i<=tot;i++) ff[i][0]=t[i].pre;
     26     for(int i=1;i<=tot;i++)
     27     {
     28        int nw=q[i];
     29        for(int j=1;j<=18;j++)
     30         ff[nw][j]=ff[ff[nw][j-1]][j-1];
     31     }
     32 }
     33 
     34 int now;
     35 struct sam
     36 {
     37     void extend(int k)
     38     {
     39         int np=++tot,p=last;
     40         t[np].step=t[last].step+1;
     41         t[np].rt=1;pos[++now]=np;
     42         while(p&&!t[p].son[k])
     43         {
     44             t[p].son[k]=np;
     45             p=t[p].pre;
     46         }
     47         if(!p) t[np].pre=1;
     48         else
     49         {
     50             int q=t[p].son[k];
     51             if(t[q].step==t[p].step+1) t[np].pre=q;
     52             else
     53             {
     54                 int nq=++tot;
     55                 memcpy(t[nq].son,t[q].son,sizeof(t[nq].son));
     56                 t[nq].step=t[p].step+1;
     57                 t[nq].pre=t[q].pre;
     58                 t[q].pre=t[np].pre=nq;
     59                 while(p&&t[p].son[k]==q)
     60                 {
     61                     t[p].son[k]=nq;
     62                     p=t[p].pre;
     63                 }
     64             }
     65         }
     66         last=np;
     67     }
     68     void init()
     69     {
     70         memset(v,0,sizeof(v));
     71         for(int i=1;i<=tot;i++) v[t[i].step]++;
     72         for(int i=1;i<=tot;i++) v[i]+=v[i-1];
     73         for(int i=tot;i>=1;i--) q[v[t[i].step]--]=i;
     74         
     75         for(int i=tot;i>=1;i--)
     76         {
     77             int nw=q[i];
     78             t[t[nw].pre].rt+=t[nw].rt;
     79         }
     80     }
     81     void ffind(int l,int r)
     82     {
     83         l=l/2+1;r=(r+1)/2;
     84         int x=pos[r];
     85         for(int i=18;i>=0;i--)
     86         {
     87             if(t[ff[x][i]].step>=r-l+1) x=ff[x][i];
     88         }
     89         ans=mymax(ans,1LL*(r-l+1)*t[x].rt);
     90     }
     91 }sam;
     92 
     93 char s[Maxn];
     94 // int a[2*Maxn],p[2*Maxn];
     95 
     96 void manacher(int l)
     97 {
     98     v[0]=99;
     99     for(int i=0;i<l;i++) v[2*i+1]=s[i]-'a'+1,v[2*i+2]=99;
    100     v[2*l+1]=110;
    101     l=2*l;
    102     int mx=0,id=0;
    103     for(int i=1;i<=l;i++)
    104     {
    105         if(i<mx) q[i]=mymin(mx-i+1,q[2*id-i]);
    106         else q[i]=1;
    107         while(v[i+q[i]]==v[i-q[i]]&&i-q[i]>=0)
    108         {
    109             q[i]++;
    110             sam.ffind(i-q[i]+1,i+q[i]-1);
    111         }
    112         if(i+q[i]-1>mx) mx=i+q[i]-1,id=i;
    113     }
    114 }
    115 
    116 int main()
    117 {
    118     scanf("%s",s);
    119     int l=strlen(s);
    120     last=tot=1;now=0;
    121     for(int i=0;i<l;i++) sam.extend(s[i]-'a'+1);
    122     sam.init();
    123     get_f();
    124     manacher(l);
    125     printf("%lld
    ",ans);
    126     return 0;
    127 }
    View Code

    2017-04-17 16:54:09

  • 相关阅读:
    Android布局尺寸思考
    正则表达式五分钟快速复习
    git gitignore文件失效处理
    华为手机Edittext光标(cursor)颜色修改
    AndroidStudio-OSX 常用快捷键整理
    OS X(EI Capitan)常用快捷键整理
    通过Foxit和坚果云实现iPad和PC的pdf同步阅读(修改,笔记)
    《程序员必读的职业规划书》职业生涯规划部分书摘及感想
    以神经网络使用为例的Matlab和Android混合编程
    写出优美代码的两个方式:一步到位VS迭代优化
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/6723691.html
Copyright © 2011-2022 走看看