题目大意:
给你一个字符串,求其中回文子串的长度*出现次数的最大值
明明是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 }