2019HDU多校 I Love Palindrome String HDU - 6599 回文树

题目链接:https://cn.vjudge.net/problem/HDU-6599

题解:输出每个长度下的回文串

题解:其实就是对于每一个本质不同的回文串,先判断他是不是符合条件(左一半是不是也是回文,这个可以用马拉车算法判断一下),符合的话,就对应长度累计加和即可。判断的时候,如果数目是偶数,就取中间两个字符的中间添加的字符,否则就取中间的字符。

#include 
using namespace std;
const int N = 3e5 + 10;
struct PT {
	int nex[N][26]; // 与字典树类似,指向下一节点
	int fail[N]; // 失配后跳转的节点
	int cnt[N]; // 节点i表示本质不同的字符串的个数
	int num[N]; 
	int len[N]; // 节点表示回文串的长度
	int S[N]; // 存放添加的字符
	int last; //上一个字符所在的节点
	int n; // 字符数组指针
	int p; // 节点指针
	int sum; // 本质不同回文串数目 
	int pid[N];
	long long Sum;
	// 新建节点 
	int newnode (int l) {
		for (int i = 0; i < 26; i++) nex[p][i] = 0;
		cnt[p] = 0;
		num[p] = 0;
		len[p] = l;
		return p++; 
	} 
	// 初始化 
	void init() {
		p = 0;
		sum = 0; 
		Sum = 0;
		newnode(0);
		newnode(-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;
	} 
	void add(int c) {
		c -= 'a';
		S[++n] = c;
		int cur = get_fail(last); // 通过上一个找这个匹配的位置 
		if(!nex[cur][c]) { // 如果没有出现过,则说明出现了个本质不同的回文串
			int now = newnode(len[cur] + 2); // 新建节点
			fail[now] = nex[get_fail(fail[cur])][c];
			nex[cur][c] = now; 
			num[now] = num[fail[now]] + 1;
			sum++;
		}
		last = nex[cur][c];
		cnt[last]++;
		pid[last] = n;
	}
	void count() {
		for(int i = p - 1; i >= 2; i--)
			cnt[fail[i]] += cnt[i], Sum += cnt[i];
	}
}a;
char str[N], s[N * 2];
int p[N * 2];
int ans[N];
int lenstr;
void Manacher() {
	s[0] = '0', s[1] = '#';
	for(int i = 0; i < lenstr; i++)	{
		s[i * 2 + 2] = str[i];
		s[i * 2 + 3] = '#';
	}
	s[lenstr * 2 + 2] = '1';
	int maxx = 0 , id;
	for(int i = 2; i <= lenstr * 2 + 1; i++) {
		p[i] = maxx > i ? min(p[id - (i - id)], maxx - i) : 1;
		while(s[i + p[i]] == s[i - p[i]]) p[i]++;
		if(i + p[i] > maxx) {
			maxx = i + p[i];
			id = i;
		}
	}
}
bool judge(int pos) {
	int id;
	// 其实这两可以合并,为了看起来方便,就不合并了 
	if(a.len[pos] & 1) {
		if(((a.len[pos] + 1) / 2 ) & 1) 
			id = (a.pid[pos] - 1 - (a.len[pos] + 1) / 2 / 2) * 2 + 2;
		else
			id = (a.pid[pos] - 1 - (a.len[pos] + 1) / 2 / 2) * 2 + 3;
	} else {
		if((a.len[pos] / 2 ) & 1) 
			id = (a.pid[pos] - 1 - a.len[pos] / 2 / 2) * 2 + 2;
		else
			id = (a.pid[pos] - 1 - a.len[pos] / 2 / 2) * 2 + 3;
	}
//	cout << a.len[pos] << " " << id << " " << p[id] << " " << a.pid[pos] << endl;
	if(p[id] >= (a.len[pos] + 1) / 2) return true;
	return false;
}
int main() {
	while(~scanf("%s", str)) {
		a.init();
	
		lenstr = strlen(str);
		for(int i = 0; i < lenstr; i ++) {
			a.add(str[i]);
			ans[i + 1] = 0;
		} 
		Manacher();
		a.count();
		for(int i = 2; i < a.p; i++) {
			if(judge(i)) {
				ans[a.len[i]] += a.cnt[i];
			}
		}
		for(int i = 1; i <= lenstr; i++)
			printf("%d%c", ans[i], " \n"[i == lenstr]);
	}
	
	return 0;
}

 

你可能感兴趣的:(回文自动机)