回文树 (tsinsen A1280. 最长双回文串)

A1280. 最长双回文串
时间限制: 2.0s   内存限制: 512.0MB  
总提交次数: 349   AC次数: 171   平均分: 65.67
将本题分享到:
       
   
试题来源
  中国国家队清华集训 2011-2012 第二天
问题描述
  顺序和逆序读起来完全一样的串叫做回文串。比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同)。
  输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串。
输入格式
  一行由小写英文字母组成的字符串S。
输出格式
  一行一个整数,表示最长双回文子串的长度。
样例输入
baacaabbacabb
样例输出
12
样例说明
  从第二个字符开始的字符串aacaabbacabb可分为aacaa与bbacabb两部分,且两者都是回文串。
数据规模及限制
  对于10%的数据,2≤|S|≤10 3
  对于30%的数据,2≤|S|≤10 4
  对于100%的数据,2≤|S|≤10 5
  时间限制:2秒

回文树先入个门
更详细的见博客 http://blog.csdn.net/u013368721/article/details/42100363

/*======================================================
# Author: whai
#
# Last modified: 2015-10-05 15:37
#
# Filename: tsinsen_A1280.cpp
======================================================*/
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <set>
#include <map>

using namespace std;

#define LL __int64
#define PB push_back
#define P pair<int, int>
#define X first
#define Y second

const int N = 1e5 + 5;
const int M = 26;

struct PalTree {
	int nxt[N][M]; //表示编号为i的节点表示的回文串在两边添加字符c以后变成的回文串的编号
	int fail[N]; //表示节点i失配以后跳转不等于自身的节点i表示的回文串的最长后缀回文串
	int cnt[N]; //表示节点i表示的本质不同的串的个数(建树时求出的不是完全的,最后count()函数跑一遍以后才是正确的)
	int num[N]; //表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数
	int len[N]; //表示编号为i的节点表示的回文串的长度(一个节点表示一个回文串)
	int S[N];
	int last, n, p;

	int new_node(int x) {
		memset(nxt[p], 0, sizeof(nxt[p]));
		cnt[p] = 0;
		num[p] = 0;
		len[p] = x;
		return p++;
	}

	void init() {
		p = 0;
		new_node(0);
		new_node(-1);
		last = 0;
		n = 0;
		S[n] = -1;
		fail[0] = 1;
	}

	int get_fail(int x) {
		while(S[n - len[x] - 1] != S[n]) x = fail[x];
		return x;
	}

	int add(int x) {
		x -= 'a';
		S[++n] = x;
		int cur = get_fail(last);
		if(!nxt[cur][x]) {
			int now = new_node(len[cur] + 2);
			fail[now] = nxt[get_fail(fail[cur])][x];
			nxt[cur][x] = now;
			num[now] = num[fail[now]] + 1;
		}
		last = nxt[cur][x];
		++cnt[last];
		return len[last];
	}

	void count() {
		for(int i = p - 1; i >= 0; --i)
			cnt[fail[i]] += cnt[i];
	}
};

PalTree pt;
int len[N];
char str[N];

void gao(char str[]) {
	int ans = 0;
	int n = strlen(str);
	pt.init();

	for(int i = n - 1; i >= 0; --i) {
		len[i] = pt.add(str[i]);
	}
	pt.init();
	for(int i = 0; i < n - 1; ++i) {
		ans = max(ans, pt.add(str[i]) + len[i + 1]);
	}
	printf("%d\n", ans);
}

int main() {
	while(scanf("%s", str) != EOF) {
		gao(str);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值