1. 程式人生 > >BZOJ 3676 [Apio2014]迴文串 (字尾自動機+manacher)

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\n",ans); 124 return 0; 125 }