BZOJ3676: [Apio2014]回文串
? 解题记录 ? ? BZOJ ? ? 回文自动机 ?    2017-11-23 11:13:58    592    0    0

Description

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

Input

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

Output


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

Sample Input

【样例输入l】
abacaba

【样例输入2]
www

Sample Output

【样例输出l】
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。

 

之前得用后缀自动机+manacher的题目有了回文自动机(回文自动机可以看这篇博客:我是忧郁的“这篇博客”)瞬间变成板子题,代码长度--,代码难度--,正确率+=inf,PAM真的是神器。但是距离熟练运用可能还有一段距离。

大致思路很清晰了,回文自动机统计每一个本质不同回文串的出现次数和长度,复杂度为O(n)。代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 3e5 + 5;

namespace PAM {
	char s[maxn];
	int trie[maxn][26], sum[maxn], fail[maxn], len[maxn];
	int cnt, pos, last;
	void init() {
		cnt = 1, pos = last = 0;
		fail[0] = 1, len[0] = 0, len[1] = -1;
	}
	int getfail(int p) {
		while(s[pos - len[p] - 1] != s[pos])
			p = fail[p];
		return p;
	}
	void add(int x) {
		int id = s[x] - 'a';
		int p = getfail(last);
		if(!trie[p][id]) {
			int now = ++cnt;
			fail[now] = trie[getfail(fail[p])][id];
			trie[p][id] = now;
			
			len[now] = len[p] + 2;
		}
		last = trie[p][id];
		++sum[last];
	}
	void push_up() {
		for(register int i = cnt; i >= 0; --i)
			sum[fail[i]] += sum[i];
	}
	void create() {
		int sl = strlen(s);
		for(register int i = 0; i < sl; ++i)
			pos = i, add(i);
		push_up();
	}
	long long cntans() {
		long long ans = 0;
		for(register int i = 2; i <= cnt; ++i)
			ans = max(ans, 1LL * len[i] * sum[i]);
		return ans;
	}
}

int main() {
	PAM::init();
	scanf("%s", PAM::s);
	PAM::create();
	printf("%lld", PAM::cntans());
}

上一篇: 洛谷P3028 [USACO10OCT]汽水机Soda Machine

下一篇: P3391 【模板】文艺平衡树(Splay)

592 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航