回文串(bzoj 3676)
Description
考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出
现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最
大出现值。
Input
输入只有一行,为一个只包含小写字母(a -z)的非空字符串s。
Output
输出一个整数,为逝查回文子串的最大出现值。
Sample Input
【样例输入l】
abacaba
【样例输入2]
www
abacaba
【样例输入2]
www
Sample Output
【样例输出l】
7
【样例输出2]
4
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。
/* 调了一个晚上,终于调出来了,二分的时候出了一些差错。 因为一个长度为n的字符串,本质不同的回文串只有n个,所以这个题很明显需要处理出所有的回文串,然后再查询字符串中它出现的次数。 提前处理出height数组,然后查询某个字串的时候,找到它的排名,向上向下二分查询次数。 */ #include<cstdio> #include<iostream> #include<cstring> #define N 300100 #define lon long long using namespace std; int s[N],t1[N],t2[N],c[N],sa[N],rank[N],height[N],n,m=26; int p[N*2],st[N][20],lg2[N]; char ch[N],s1[N*2];lon ans; bool cmp(int *y,int a,int b,int k){ int a1=y[a],b1=y[b]; int a2=a+k<n?y[a+k]:-1; int b2=b+k<n?y[b+k]:-1; return a1==b1&&a2==b2; } void DA(){ int *x=t1,*y=t2; for(int i=0;i<m;i++) c[i]=0; for(int i=0;i<n;i++) c[x[i]=s[i]]++; for(int i=1;i<m;i++) c[i]+=c[i-1]; for(int i=n-1;~i;i--) sa[--c[x[i]]]=i; for(int k=1,p=0;k<=n;k*=2,m=p,p=0){ for(int i=n-k;i<n;i++) y[p++]=i; for(int i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k; for(int i=0;i<m;i++) c[i]=0; for(int i=0;i<n;i++) c[x[y[i]]]++; for(int i=1;i<m;i++) c[i]+=c[i-1]; for(int i=n-1;~i;i--) sa[--c[x[y[i]]]]=y[i]; swap(x,y);p=1;x[sa[0]]=0; for(int i=1;i<n;i++) if(cmp(y,sa[i-1],sa[i],k)) x[sa[i]]=p-1; else x[sa[i]]=p++; if(p>=n) break; } } void get_ht(){ for(int i=0;i<n;i++) rank[sa[i]]=i; for(int i=0,j,k=0;i<n;height[rank[i++]]=k){ if(!rank[i]) continue; j=sa[rank[i]-1];k=k?k-1:k; while(j+k<n&&i+k<n&&s[i+k]==s[j+k]) k++; } memset(st,127/3,sizeof(st)); for(int i=0;i<n;i++) st[i][0]=height[i]; for(int i=2;i<=n;i++) lg2[i]=lg2[i>>1]+1; for(int j=1;1<<j<=n;j++) for(int i=0;i+(1<<j)-1<n;i++) st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]); } int query(int l,int r){ if(l>r) return 0; int k=lg2[r-l+1]; return min(st[l][k],st[r-(1<<k)+1][k]); } lon solve(int l,int r){ l=(l&1)?l/2:l/2-1; r=(r&1)?r/2-1:r/2-1; if(l==0&&r==1){ int aa=1; } int pos=rank[l],L=-1,R=pos,tmp1=pos,tmp2=pos; while(L<R-1){ int mid=L+R>>1; if(query(mid+1,pos)>=r-l+1) R=mid,tmp1=mid; else L=mid; } L=pos;R=n; while(L<R-1){ int mid=L+R>>1; if(query(pos+1,mid)>=r-l+1) L=mid,tmp2=mid; else R=mid; } return (lon)(tmp2-tmp1+1)*(r-l+1); } void manacher(){ int len=n*2+1; s1[0]='$';s1[len]='#'; for(int i=0;i<n;i++){ s1[i*2+1]='#'; s1[i*2+2]=ch[i]; } p[1]=1;int pos=1,maxr=1; for(int i=2;i<=len;i++){ if(i<maxr) p[i]=min(maxr-i,p[pos*2-i]); else p[i]=1; while(s1[i+p[i]]==s1[i-p[i]]){ if(i+p[i]>maxr) ans=max(ans,solve(i-p[i],i+p[i])); p[i]++; } if(i+p[i]>maxr) pos=i,maxr=i+p[i]; } } int main(){ scanf("%s",ch);n=strlen(ch); for(int i=0;i<n;i++) s[i]=ch[i]-'a'; DA();get_ht(); manacher(); cout<<ans; return 0; }