bzoj3676-回文串

给出一个字符串,一个子串的出现值为字串出现次数乘以长度,求所有回文串中最大的出现值。

分析

回文自动机模版题,建出自动机后直接统计即可。

回文自动机

类似于后缀自动机,不过一条边\((u,v,c)\)的含义是在\(u\)点的串左右两边加上字母\(c\)可以得到\(v\)点代表的串。它的\(fail\)指针和AC自动机类似。这里有一个重要的简化代码,就是开始时设两个点,\(len\)长度分别为0和-1,两个点的fail指针互相指对方,这样可以保证奇数长度回文串长度从1开始,直接-1+2即可。fail往前跳的时候一定能够跳到0号点或1号点。这种写法还是很好的。

代码

#include<cstdio>
#include<cctype>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long giant;
int read() {
	int x=0,f=1;
	char c=getchar();
	for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
	for (;isdigit(c);c=getchar()) x=x*10+c-'0';
	return x*f;
}
const int maxn=3e5+1;
const int maxc=26;
struct PAM {
	int s[maxn],n,t[maxn][maxc],len[maxn],link[maxn],cnt[maxn],last,tot;
	PAM () {
		last=tot=1;
		s[n=0]=-1;
		len[0]=0,len[1]=-1;
		link[0]=1,link[1]=0;
	}
	int fail(int x) {
		for (;s[n-len[x]-1]!=s[n];x=link[x]);
		return x;
	}
	void add(int x) {
		s[++n]=x;
		last=fail(last);
		if (!t[last][x]) {
			int nw=++tot;
			len[nw]=len[last]+2;
			link[nw]=t[fail(link[last])][x];
			t[last][x]=nw;
		}
		++cnt[last=t[last][x]];
	}
	giant run() {
		giant ans=0;
		for (int i=tot;i>1;--i) cnt[link[i]]+=cnt[i],ans=max(ans,(giant)cnt[i]*len[i]);		
		return ans;
	}
} pam;
char s[maxn];
int main() {
	#ifndef ONLINE_JUDGE
	freopen("test.in","r",stdin);
	#endif
	scanf("%s",s+1);
	int n=strlen(s+1);
	for (int i=1;i<=n;++i) pam.add(s[i]-'a');
	printf("%lld\n",pam.run());
	return 0;
}
posted @ 2017-04-17 20:22  permui  阅读(210)  评论(0编辑  收藏  举报