zoukankan      html  css  js  c++  java
  • BZOJ 3676 [Apio2014]回文串 (后缀自动机+manacher/回文自动机)

    题目大意:

    给你一个字符串,求其中回文子串的长度*出现次数的最大值

    明明是PAM裸题我干嘛要用SAM做

    回文子串有一个神奇的性质,一个字符串本质不同的回文子串个数是$O(n)$级别的

    用$manacher$的思想分析一下,$maxright$指针向右扩展才会产生新的回文串

    其它的回文串都根据之前求得的信息得到的,比如根据回文中心对称,或者是不超过当前最长回文上限

    每次扩展成功时,都把这个回文串放到$SAM$里跑

    预处理出每个前缀结尾在$SAM$里的节点编号,就不用每次都从头跑了

    沿着$pre$指针倍增地往上跳,直到跳到当前节点能表示出这个回文串为止

    注意长度为1的串的情况

    如果被卡空间了,会发现预处理以后,trs指针没什么用了,把它当成倍增的数组吧

      1 #include <cmath>
      2 #include <vector>
      3 #include <cstdio>
      4 #include <cstring>
      5 #include <algorithm>
      6 #define N1 305000
      7 #define S1 (N1<<1)
      8 #define T1 (N1<<2)
      9 #define ll long long
     10 #define uint unsigned int
     11 #define rint register int 
     12 #define dd double
     13 #define il inline 
     14 #define inf 0x3f3f3f3f
     15 #define idx(X) (X-'a')
     16 using namespace std;
     17 
     18 int gint()
     19 {
     20     int ret=0,fh=1;char c=getchar();
     21     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
     22     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
     23     return ret*fh;
     24 }
     25 int n,m,len;
     26 /*struct Edge{
     27 int head[S1],to[S1],nxt[S1],cte;
     28 void ae(int u,int v){
     29     cte++;to[cte]=v,nxt[cte]=head[u],head[u]=cte;}
     30 }E;*/
     31 namespace SAM{
     32 int trs[S1][26],pre[S1],dep[S1],ed[S1],pos[S1],la,tot;
     33 void init(){tot=la=1;}
     34 void insert(int c,int id)
     35 {
     36     int p=la,np=++tot,q,nq;la=np;
     37     dep[np]=dep[p]+1;
     38     pos[id]=np,ed[np]=1;
     39     for(;p&&!trs[p][c];p=pre[p]) trs[p][c]=np;
     40     if(!p) {pre[np]=1;return;}
     41     q=trs[p][c];
     42     if(dep[q]==dep[p]+1) pre[np]=q;
     43     else{
     44         pre[nq=++tot]=pre[q];
     45         pre[q]=pre[np]=nq;
     46         dep[nq]=dep[p]+1;
     47         memcpy(trs[nq],trs[q],sizeof(trs[q]));
     48         for(;p&&trs[p][c]==q;p=pre[p]) trs[p][c]=nq;
     49     }
     50 }
     51 int hs[S1],que[S1],sz[S1];
     52 //int ff[S1][20];
     53 void build()
     54 {
     55     int i,j,x;
     56     for(i=1;i<=tot;i++) hs[dep[i]]++;
     57     for(i=1;i<=n;i++) hs[i]+=hs[i-1];
     58     for(i=1;i<=tot;i++) que[hs[dep[i]]--]=i;
     59     for(i=tot;i;i--)
     60     {
     61         x=que[i];//E.ae(pre[x],x);
     62         if(ed[x]) sz[x]++;
     63         sz[pre[x]]+=sz[x];
     64         trs[x][0]=x,trs[x][1]=pre[x];
     65     }
     66     for(j=2;j<=20;j++)
     67         for(i=1;i<=tot;i++)
     68         trs[i][j]=trs[ trs[i][j-1] ][j-1];
     69 }
     70 int solve(int x,int s,int e)
     71 {
     72     int fx,L=e-s+1;
     73     for(int j=20;j>=0;j--)
     74     //for(int j=5;j>=0;j--)
     75     {
     76         if(!trs[x][j]) continue;
     77         fx=trs[x][j];
     78         if(dep[fx]>=L) x=fx;
     79     }
     80     return sz[x];
     81 }
     82 };
     83 char str[N1],man[S1];
     84 int p[S1],hs[30];
     85 
     86 int main()
     87 {
     88     //freopen("t1.in","r",stdin);
     89     scanf("%s",str+1);
     90     n=strlen(str+1);
     91     man[0]='$',man[1]='#';
     92     int i,j,mr=2,mid=1,l,r,x;
     93     SAM::init();
     94     for(i=1;i<=n;i++) SAM::insert(idx(str[i]),i);
     95     SAM::build();
     96     for(i=1;i<=n;i++) man[2*i]=str[i],man[2*i+1]='#';
     97     p[1]=1;
     98     ll ans=0;
     99     for(i=2;i<=2*n+1;i++)
    100     {
    101         if(i<mr) p[i]=min(p[2*mid-i],mr-i);
    102         else p[i]=1;
    103         while(man[i-p[i]]==man[i+p[i]])
    104         {
    105             if(!((i+p[i])&1))
    106             {
    107                 l=(i-p[i])>>1;
    108                 r=(i+p[i])>>1;
    109                 x=SAM::pos[r];
    110                 ans=max(ans,1ll*(r-l+1)*SAM::solve(x,l,r));
    111             }
    112             p[i]++;
    113         }
    114         if(i+p[i]>mr) mr=i+p[i],mid=i;
    115     }
    116     for(i=1;i<=n;i++)
    117         if(!hs[idx(str[i])])
    118         {
    119             hs[idx(str[i])]=1;
    120             l=i,r=i,x=SAM::pos[r];
    121             ans=max(ans,1ll*SAM::solve(x,l,r));
    122         }
    123     printf("%lld
    ",ans);
    124     return 0;
    125 }

    进入正题

    这明明是一道$PAM$裸题嘛

    $PAM$的构造方式类似于$AC$自动机..但它仍然有许多美妙的性质

    比如奇回文树是树根节点深度设为-1等等...

    而且$PAM$代码非常短

     1 #include <cmath>
     2 #include <vector>
     3 #include <cstdio>
     4 #include <cstring>
     5 #include <algorithm>
     6 #define N1 301000
     7 #define S1 (N1<<1)
     8 #define ll long long
     9 #define uint unsigned int
    10 #define rint register int 
    11 #define dd double
    12 #define il inline 
    13 #define inf 0x3f3f3f3f
    14 #define idx(X) (X-'a')
    15 using namespace std;
    16 
    17 int gint()
    18 {
    19     int ret=0,fh=1;char c=getchar();
    20     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
    21     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
    22     return ret*fh;
    23 }
    24 int n,len,cnt;
    25 namespace PAM{
    26 int trs[N1][26],pre[N1],dep[N1],sz[N1],la,tot;
    27 void init(){la=tot=1,pre[0]=pre[1]=1,dep[1]=-1;}
    28 int ntsym(char *str,int i,int p){return str[i-dep[p]-1]!=str[i]?1:0;}
    29 void insert(char *str,int i)
    30 {
    31     int p=la,np,fp,c=idx(str[i]);
    32     while(ntsym(str,i,p)) p=pre[p];
    33     if(!trs[p][c])
    34     {
    35         np=++tot;
    36         dep[np]=dep[p]+2;
    37         fp=pre[p];
    38         while(ntsym(str,i,fp)) fp=pre[fp];
    39         pre[np]=trs[fp][c];
    40         trs[p][c]=np;
    41     }
    42     la=trs[p][c];
    43     sz[trs[p][c]]++;
    44     return;
    45 }
    46 ll topo()
    47 {
    48     ll ans=0;
    49     for(int x=tot;x>1;x--)
    50         sz[pre[x]]+=sz[x],ans=max(ans,1ll*dep[x]*sz[x]);
    51     return ans;
    52 }
    53 };
    54 char str[N1];
    55 
    56 int main()
    57 {
    58     //freopen("t2.in","r",stdin);
    59     //freopen("a.out","w",stdout);
    60     int i;PAM::init();
    61     scanf("%s",str+1);len=strlen(str+1);
    62     for(i=1;i<=len;i++) PAM::insert(str,i);
    63     printf("%lld
    ",PAM::topo());
    64     return 0;
    65 }
  • 相关阅读:
    1295. 统计位数为偶数的数字『简单』
    1281. 整数的各位积和之差『简单』
    697. 数组的度『简单』
    748. 最短完整词『简单』
    832. 翻转图像『简单』
    1446. 连续字符『简单』
    1455. 检查单词是否为句中其他单词的前缀『简单』
    1160. 拼写单词『简单』
    1304. 和为零的N个唯一整数『简单』
    1103. 分糖果 II『简单』
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10118672.html
Copyright © 2011-2022 走看看