[bzoj3676] [APIO2014]回文串

Description

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

Input

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

Output

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

Sample Input

abacaba 

Sample Output

7 

Solution

SA+manacher。

考虑\(manacher\)的过程中,本质不同的回文串只会在每次扩展的时候出现,所以每次扩展的时候上下二分,然后算一下就好了。

复杂度\(O(n\log n)\)

注意\(manacher\)之前会把原串翻倍,在翻倍之前就把\(sa\)建好,否则卡不过。。

(其实这题正解是回文自动机来着。。那玩意貌似是O(n)的)

#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
 
void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}

#define ll long long 
 
void print(ll x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(ll x) {if(!x) putchar('0');else print(x);putchar('\n');}

const int maxn = 6e5+10;

char c[maxn],s[maxn];
int n,f[maxn];
ll ans;

int spx[maxn],spy[maxn],sum[maxn],sa[maxn],m,rk[maxn],height[maxn],st[maxn][20],lg[maxn],len;

void get_sa() {
	m=240;int p=0,*x=spx,*y=spy;
	for(int i=1;i<=n;i++) sum[x[i]=c[i]]++;
	for(int i=1;i<=m;i++) sum[i]+=sum[i-1];
	for(int i=n;i;i--) sa[sum[x[i]]--]=i;
	
	for(int tot=0,k=1;p<n;k<<=1,tot=0) {
		p=0;
		for(int i=n-k+1;i<=n;i++) y[++tot]=i;
		for(int i=1;i<=n;i++) if(sa[i]>k) y[++tot]=sa[i]-k;

		for(int i=1;i<=m;i++) sum[i]=0;
		for(int i=1;i<=n;i++) sum[x[y[i]]]++;
		for(int i=1;i<=m;i++) sum[i]+=sum[i-1];
		for(int i=n;i;i--) sa[sum[x[y[i]]]--]=y[i];

		swap(x,y);x[sa[1]]=p=1;
		for(int i=2;i<=n;i++)
			if(y[sa[i]]!=y[sa[i-1]]||y[sa[i]+k]!=y[sa[i-1]+k]) x[sa[i]]=++p;
			else x[sa[i]]=p;
		m=n;
	}
}

void get_height() {
	for(int i=1;i<=n;i++) rk[sa[i]]=i;
	int p=1;
	for(int i=1;i<=n;i++) {
		if(p) p--;
		while(c[i+p]==c[sa[rk[i]-1]+p]) p++;
		height[rk[i]]=p;
	}
}

void rmq_init() {
	for(int i=1;i<=n;i++) st[i][0]=height[i];
	for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
	for(int i=1;i<=18;i++)
		for(int j=1;j<=n;j++)
			st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
}

int get_rmq(int l,int r) {
	if(r<l) return r=l;
	int w=lg[r-l+1];
	return min(st[l][w],st[r-(1<<w)+1][w]);
}

void get_ans(int lpos,int rpos,int xx) {
	if(s[lpos]=='&') return ;
	lpos/=2,rpos/=2;
	int w=rk[lpos];
	int l=1,r=w,ret=w,mid,Len=rpos-lpos+1;
	while(l<=r) {
		mid=(l+r)>>1;
		if(get_rmq(mid+1,w)>=Len) ret=mid,r=mid-1;
		else l=mid+1;
	}
	int ret2=w;l=w,r=len;
	while(l<=r) {
		mid=(l+r)>>1;
		if(get_rmq(w+1,mid)>=Len) ret2=mid,l=mid+1;
		else r=mid-1;
	}
	ans=max(ans,1ll*(ret2-ret+1)*xx);
}

int main() {
	char e=getchar();
	while(e!=EOF&&e!='\n') c[++len]=e,e=getchar();
	
	n=len;get_sa(),get_height(),rmq_init();

	s[n=0]='$',s[++n]='&';
	for(int i=1;i<=len;i++) s[++n]=c[i],s[++n]='&';
	
	int mr=1,mid=1;
	for(int i=1;i<=n;i++) {
		f[i]=min(mr-i,f[mid*2-i]);
		while(s[i-f[i]]==s[i+f[i]]) get_ans(i-f[i],i+f[i],f[i]+1),f[i]++;
		if(i+f[i]>mr) mr=i+f[i],mid=i;
	}
	write(ans);
	return 0;
}
posted @ 2019-01-17 21:13  Hyscere  阅读(82)  评论(0编辑  收藏  举报