Live2D

Solution -「NOI.AC 省选膜你赛」T2

  这道题就叫 T2 我有什么办法www

题目

题意简述

  给定一个字符串 s,其长度为 n,求无序子串对 (u,v) 的个数,其中 (u,v) 满足 u,v 均为回文串且出现位置相交。

数据规模

  n2×106,字符集为小写字母(于是测试数据里有神奇的'{'字符

题解

  难得的水题呐!

  正难则反,首先求出总的回文子串对数,再减去出现位置不交的对数。

  对于前者,用 Manacher 或者 PAM 都可以轻松求出,这里用的 PAM。

  对于后者,记 f(i) 为原串中以 i 结尾的回文串个数,g(i)s[i..n] 中的回文子串个数。那么不交的回文子串对的对数为:

i=1n1f(i)g(i+1)

  fg 亦能用 PAM 求出,这道题就解决啦~

  最后测试数据出锅,AC 失败qwq。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>

const int MAXN = 2e6, MOD = 998244353, INV2 = 499122177;
char s[MAXN + 5];
int preend[MAXN + 5], sufend[MAXN + 5];

class PalindromeAutomaton {
private:
	int cnt, lst, ch[MAXN + 5][26], len[MAXN + 5], link[MAXN + 5], dep[MAXN + 5];

public:
	PalindromeAutomaton (): cnt ( 1 ), lst ( 1 ), len { 0, -1 }, link { 1, 0 } {}
	inline void clear () {
		for ( int i = 0; i <= cnt; ++ i ) {
			dep[i] = link[i] = len[i] = 0;
			for ( int j = 0; j < 26; ++ j ) ch[i][j] = 0;
		}
		cnt = lst = 1, len[1] = -1, link[0] = 1;
	}
	inline int build ( const char* str, int* endcnt ) {
		int ret = 0;
		for ( int i = 1; str[i]; ++ i ) {
			int cid = str[i] - 'a', p = lst;
			for ( ; str[i] ^ str[i - len[p] - 1]; p = link[p] );
			if ( ! ch[p][cid] ) {
				int cur = ++ cnt, q = link[p]; len[cur] = len[p] + 2;
				for ( ; str[i] ^ str[i - len[q] - 1]; q = link[q] );
				dep[cur] = dep[link[cur] = ch[q][cid]] + 1, ch[p][cid] = cur;
			}
			ret = ( ret + ( endcnt[i] = dep[lst = ch[p][cid]] ) ) % MOD;
		}
		return ret;
	}
} pam;

int main () {
	scanf ( "%s", s + 1 );
	int ans = pam.build ( s, preend ), n = strlen ( s + 1 );
	ans = ( ans * ( ans - 1ll ) % MOD * INV2 % MOD + MOD ) % MOD;
	pam.clear (), std :: reverse ( s + 1, s + n + 1 );
	pam.build ( s, sufend ), std :: reverse ( sufend + 1, sufend + n + 1 );
	for ( int i = n - 1; i; -- i ) sufend[i] = ( sufend[i + 1] + sufend[i] ) % MOD;
	for ( int i = 1; i < n; ++ i ) ans = ( ( ans - 1ll * preend[i] * sufend[i + 1] % MOD ) % MOD + MOD ) % MOD;
	printf ( "%d\n", ans );
	return 0;
}
posted @   Rainybunny  阅读(109)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示