【字符串】回文自动机 - 模板

解决字符串中回文串的相关问题

/*
---------------回文自动机PAM---------------

- 传入字符串下标从0开始
- 本质不同的回文子串个数
- 所有回文子串个数
- 每种回文串出现的次数 cnt(需要get_cnt)
- 每种回文串的长度 len
- 以下标 i 为结尾的回文串的个数 sed
- 每个回文串在原串中出现的起始位置 record
*/

struct PAM {
	string s;
	int n;
	int nxt[N][26];
	int fail[N]; // 当前节点最长回文后缀的节点
	int len[N]; // 当前节点表示的回文串的长度
	int cnt[N]; // 当前节点回文串的个数, 在getcnt后可得到全部
	int sed[N]; // 以当前节点为后缀的回文串的个数
	int record[N]; // 每个回文串在原串中出现的位置
	int tot; // 节点个数
	int last; // 上一个节点
	void init()
	{
		tot = 0;
		memset(fail, 0, sizeof fail);
		memset(cnt, 0, sizeof cnt);
		memset(sed, 0, sizeof sed);
		memset(len, 0, sizeof len);
		memset(nxt, 0, sizeof nxt);
		memset(record, 0, sizeof record);
	}
	int newnode(int lenx)
	{
		for (int i = 0; i < 26; i++)
		nxt[tot][i] = 0;
		sed[tot] = cnt[tot] = 0;
		len[tot] = lenx;
		return tot;
	}
	void build(string ss)
	{
		tot = 0;
		newnode(0);
		tot = 1, last = 0;
		newnode(-1);
		fail[0] = 1;
		n = ss.size();
		s = " " + ss;
	}
	int getfail(int x, int n)
	{
		while (n - len[x] - 1 <= 0 || s[n - len[x] - 1] != s[n])
			x = fail[x];
		return x;
	}
	void insert(char cc, int pos)
	{
		int c = cc - 'a';
		int p = getfail(last, pos);
		if (!nxt[p][c])
		{
			tot++;
			newnode(len[p] + 2);
			fail[tot] = nxt[getfail(fail[p], pos)][c];
			len[tot] = len[p] + 2;
			sed[tot] = sed[fail[tot]] + 1;
			nxt[p][c] = tot;
		}
		last = nxt[p][c];
		cnt[last]++;
		record[last] = pos;
	}
	void insert()
	{
		for (int i = 1; i <= n; i++) insert(s[i], i);
	}
	void get_cnt()
	{
		for (int i = tot; i > 0; i--)
			cnt[fail[i]] += cnt[i];
	}
	int get_diff_cnt() // 本质不同的回文子串个数
	{
		return tot - 1;
	}
	int get_all_cnt() // 所有回文子串个数(本质相同的多次计算)
	{
		int sum = 0;
		get_cnt();
		for (int i = 2; i <= tot; i ++ ) sum += cnt[i];
		return sum;
	}
} pam;
//------------------------------------
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Texcavator

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值