牛客23多校第二场G - Link with Centrally Symmetric Strings

题意

给出一个长度为 n(b106)n(b\leq 10^6) 的字符串 SS,问 SS 是否能表示成一个或若干个好回文串拼接而成的形式。即判断:S=T1+T2++TkS=T_1+T_2+\dots +T_k 是否成立。

好回文串的定义如下:

  • 由字符 o\tt o,s\tt s,x\tt x,z\tt z 之一组成的长度为 11 的字符串是好回文串
  • bSq\mathtt{b}S\mathtt{q}dSp\mathtt{d}S\mathtt{p}pSd\mathtt{p}S\mathtt{d}qSb\mathtt{q}S\mathtt{b}nSu\mathtt{n}S\mathtt{u}uSn\mathtt{u}S\mathtt{n}oSo\mathtt{o}S\mathtt{o}sSs\mathtt{s}S\mathtt{s}xSx\mathtt{x}S\mathtt{x}zSz\mathtt{z}S\mathtt{z} 都是好回文串,其中 SS 是一个好回文串

思路

先判断一个字符串是否为好回文串

可以改造 Manacher 算法,直接更改 Manacher 算法的匹配规则即可。

int mid = 0;
int limR = 0;
for (int i=1; i<=str_n; i++)
{
    if(i < limR)
        p[i] = min(p[mid-(i-mid)], limR-i);
    else
        p[i] = 0;
    
    //直接更改 Manacher 算法的匹配规则即可。
    //while (str[ i+p[i] ] == str[ i-p[i] ])
    while (str[ i+p[i] ] == rev(str[ i-p[i] ]))
        p[i] ++;
    
    if(i+p[i] > limR)
    {
        mid = i;
        limR = i+p[i];
    }
}

直接更改 Manacher 算法的匹配规则的正确性

注意此代码:

if(i < limR)
    p[i] = min(p[mid-(i-mid)], limR-i);

此代码的作用是:如果当前回文中心 ii 被包含在前面某个延伸到最右方的回文串(回文中心是 midmid,延伸到最右方的位置为 limRlimR)中,那么可以将 iimidmid 为对称中心,对称到 ii'

min(pi,limRi)\min(p_{i'},limR-i) 即为当前回文中心 ii 的回文串长度的最小值。

注意到,bSq\mathtt{b}S\mathtt{q}qSb\mathtt{q}S\mathtt{b}dSp\mathtt{d}S\mathtt{p}pSd\mathtt{p}S\mathtt{d}nSu\mathtt{n}S\mathtt{u}uSn\mathtt{u}S\mathtt{n} 都是好回文串

如果以 ii 为回文中心的回文串是 bSq\mathtt{b}S\mathtt{q} 的形式,那么以 ii' 为回文中心的回文串就一定是 qSb\mathtt{q}S\mathtt{b} 的形式。

如果只有 bSq\mathtt{b}S\mathtt{q}好回文串,而 qSb\mathtt{q}S\mathtt{b} 不是好回文串,那么就不能直接更改 Manacher 算法的匹配规则。

换句话说,无论匹配规则是什么,只要满足正串是回文串 \Leftrightarrow 反串是回文串,那么就一定能用 Manacher 算法,否则就一定不能用。

如何判断 SS 是否能表示成好回文串拼接而成的形式

请回顾:

  • 如果 T+S+TT+S+T' 是一个回文串,那么 SS 一定是一个回文串。并且如果 TT 是一个回文串,那么 TT' 一定也是一个回文串。
  • 如果 SS 是一个回文串,那么 SS 的反串也是回文串。

但是,可以从前往后扫描字符串。

记之前某个延伸到最右方的回文串的延伸到最右方的位置为 limRlimR

对于位置 ii,如果以 ii 为回文中心的回文串最左边能延伸到的位置 limR\leq limR,说明以 ii 为回文中心的回文串能将 ii 及其之前的位置覆盖完全,此时更新 limRlimRlimR+(ilimR)1limR+(i-limR)-1

如果最后 limRnlimR\geq n,说明回文串可以将整个字符串完全覆盖,否则不行。

例如:

字符串 cbaxabcpqpcbqbcpqp\tt cbaxabcpqpcbqbcpqp,可以有这样的划分:cbaxabcycbcbqbcbcy\tt \textcolor{blue}{cbaxabc}\textcolor{red}{ycbcbqbcbcy}

但是如果按照上述方法划分,则划分的字符串为:cbaxabcycbcbqbcbcy\tt \textcolor{blue}{cbaxabc}\textcolor{red}{y}\textcolor{green}{cbcbqbcbc}\textcolor{red}{y}

不难发现,在从左往右扫描的过程中,如果发现一段回文串能覆盖之前的,那么是可以贪心的选择的。因为如果当前回文串被包含在了后面的更长的回文串中,那么后面会有一段与之对称的回文串。