[SHOI2011] 双倍回文

\(\text{Solution}\)

一道回文树的模板题,只需一直跳\(fail\)指针,直到\(len_{fail[x]}\)为串\(x\)的一半。但这要显然会时超,考虑一个优化,因为对于回文树上的节点本身即是拓扑序,只需反向枚举就不会再重复枚举。

\(\text{Code}\)

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 5e5 + 5;
int len[N],tot,pre,fail[N],sz,ch[N][27],n;
char s[N],s1[N];

int add_nd(int x) {len[++sz] = x; return sz;}
int getl(int x){for (; s[tot] != s[tot - len[x] - 1]; x = fail[x]); return x;}
void insert(char c)
{
	s[++tot] = c; int res = getl(pre);
	if (!ch[res][c - 'a'])
	{
		int x = add_nd(len[res] + 2);
		fail[x] = ch[getl(fail[res])][c - 'a'];
		ch[res][c - 'a'] = x;
	}
	pre = ch[res][c - 'a'];
}
int main()
{
	scanf("%d",&n);
	scanf("%s",s1 + 1);
	s[0] = '$',sz = -1,add_nd(0),add_nd(-1),fail[0] = 1;
	for (int i = 1; i <= n; i++) insert(s1[i]);
	int ans = 0;
	for (int i = sz; i >= 2; i--)
		if (len[i] % 4 == 0 && len[i] > ans) 
		{
			int x = fail[i],flag = 0;
			for (; len[x] * 2 >= len[i]; x = fail[x])
				if (len[x] * 2 == len[i]) flag = 1;
			if (flag) ans = max(ans,len[i]);
		}
	printf("%d\n",ans);
}
posted @ 2022-07-10 21:31  RiverSheep  阅读(31)  评论(0)    收藏  举报